移植C代码;需要按位操作和指针语法的帮助

时间:2009-12-13 00:06:26

标签: java c pointers bit-manipulation porting

我有一些我想要移植到java的C代码。我没有做太多的C编码,但我能够跟进,直到这个功能。如果有人能帮助我了解正在发生的事情,我将不胜感激。

int reverse_integer(int input) {
    int output = 0, i;

    for ( i=0, i<sizeof(int); i++ ) {
         output = ( input & 0x000000FF ) | output; 
         input >>= 8;
         if ( i < 3 ) {
             output <<= 8;
         }
    }

    return output;
}

该功能如下使用:

char * position = //some data

/*the included comment on this next line states its the size of a string*/
int i = reverse_integer( *(int*)position ) 

6 个答案:

答案 0 :(得分:7)

我很乐意发布与C代码相同的Java代码,但前提是您承诺不使用它。

/** Reverses the bytes in an integer. */
   public static int reverseInteger(int input) {
      return
         (input >>> 24) |
         (input >> 8) & 0x0000ff00 |
         (input << 8) & 0x00ff0000 |
         (input << 24);
   }

请注意,循环没有意义 - Java中的int总是4个字节。另请注意表达式开头处的三重直角括号,以执行无符号右移。

现在出于不使用它的原因:

1 - 该功能已存在 - 请参阅Integer.reverseBytes(int)

2 - 您将很难使用该示例代码,因为Java不允许您像其他任何东西一样投射字节数组。 Java是官方的big-endian(最重要的字节优先),所以如果你从文件中读取字节,那么你可以使用java.io.DataInputStream来提取整数,长整数等。

答案 1 :(得分:5)

它正在反转整数的字节顺序( endianness )。

程序员使用3似乎还有一个错误,假设它是sizeof(int) - 1

答案 2 :(得分:2)

此功能存在一个非常严重的问题:它正在解决具有可用解决方案的标准问题。简而言之,它正在重新发明轮子。

好吧,我在这里做一个假设。我假设反转整数的原因是从little-endian转换为big-endian或反之亦然。通常的原因是您使用的是小端计算机(任何Intel或AMD x86芯片),您需要以“网络顺序”(即big-endian)从网络发送矿石接收数据。

如果我的假设是正确的,在C中你可以打电话给其中一个:

ntohl()
hlton()

这里有关于这些功能的更多信息:

http://www.codeguru.com/forum/showthread.php?t=298741

如果您已经在大端计算机上,并且由于某些其他原因想要反转整数,那么这些调用对您没有帮助(因为“网络订单” 大 - endian,所以如果你已经在大端计算机上,hlton()将不会改变任何东西。)

我在谷歌搜索“Java ntohl”并找到了这些链接:

http://www.velocityreviews.com/forums/t139571-ntohl-ntohs-etc.html

http://www.coderanch.com/t/366549/Java-General/java/Java-equivilent-c-functions-htonl

所以,我认为你可能根本不需要移植它;你也许可以从这两个链接之一中获取解决方案。

答案 3 :(得分:1)

在big endian和little endian数据之间进行转换时,该函数正在按字节顺序反转。大多数网络协议要求32位整数以Big Endian顺序存储,但Intel处理器以Little Endian顺序存储数字,因此在向网络读取或写入数据时需要交换字节顺序。 (这适用于低级别的东西,而不适用于HTTP等协议,其中数字作为文本传输。)

我相信该函数实际上会编译为常规Java,但sizeof(int)除外,你可以用4代替,因为JVM将int定义为32位宽(在C中,有没有保证)。

看起来position是二进制数据块,而不是字符串。位置类型为char *,表示指向字符的指针(1个字节)。

表达式*position将取消引用该指针,获取它指向的1个字节。但是,代码的作者想要从数据块中获得完整int的字节数。 (如果针对32位架构进行编译,则为4个字节;对于64位计算机,则为8个字节。)

因此,要获得完整的int,指针将从字节指针转换为int指针:(int *)position。然后,因为我们想要该地址的值,我们在前面贴上一个星号来取消引用它:*(int *)position

答案 4 :(得分:1)

[评论太大] 如果您将output <<= 8放在循环的开头,则可以避免一个if

#include <limits.h>
int reverse_integer(int input) {
    int output = 0, i;

    for (i = 0; i < sizeof input; i++) {
         output <<= CHAR_BIT;
         output = (input & ((1 << CHAR_BIT) - 1)) | output; 
         input >>= CHAR_BIT;
    }
    return output;
}

此函数反转int中的字节。 在0x12345678为8且CHAR_BIT为4(现在最常见)的实施中,sizeof (int)的输入会返回0x78563412。< / p>

答案 5 :(得分:0)

我建议使用以下代码进行字节交换:

U16
Swap16
(
    U16 x
)
{
    return (0xFF00 & x) >> 8 | (0x00FF & x) << 8;
}


U32
Swap32
(
    U32 x
)
{
#if defined(__i386__)
    __asm__("bswap   %0" : "+r" (x));
    return x;
#else
    return (0xFF000000 & x) >> 24 |
           (0x00FF0000 & x) >> 8 |
           (0x0000FF00 & x) << 8 |
           (0x000000FF & x) << 24;
#endif
}


U64
Swap64
(
    U64 x
)
{
#if defined(__i386__)
    __asm__("bswap   %%eax\n\t"
            "bswap   %%edx\n\t"
            "xchgl   %%eax, %%edx" : "+A" (x));
    return x;
#elif defined(__x86_64__)
    __asm__("bswap   %0" : "+r" (x));
    return x;
#else
    return (0xFF00000000000000LL &
            x) >> 56 | (0x00FF000000000000LL & x) >> 40
           | (0x0000FF0000000000LL &
              x) >> 24 | (0x000000FF00000000LL & x) >> 8
           | (0x00000000FF000000LL &
              x) << 8 | (0x0000000000FF0000LL & x) << 24
           | (0x000000000000FF00LL &
              x) << 40 | (0x00000000000000FFLL & x) << 56;
#endif
}

其中U16,U32和U64为该大小的整数类型。

asm适用于gcc。