从char *数组中读取“整数”大小的字节。

时间:2009-02-13 06:34:30

标签: c++ c endianness

我想从sizeof(int)数组中读取char*个字节。

a)在什么情况下我们需要担心是否需要检查字节顺序?

b)如何考虑或不考虑字节顺序,你将如何读取前4个字节。

编辑:我读过的sizeof(int)字节需要与整数值进行比较。

解决此问题的最佳方法是什么

9 个答案:

答案 0 :(得分:19)

你的意思是什么?:

char* a;
int i;
memcpy(&i, a, sizeof(i));

如果数据来源来自不同的平台,例如设备,则只需担心内联性。

答案 1 :(得分:9)

a)如果数据是在big-endian机器上创建的,并且正在小端机器上处理,反之亦然,你只需要担心“字节序”(即字节交换)。有很多方法可以实现,但这里有几个例子。

  1. 您通过套接字在Windows计算机上接收数据。 Windows采用little-endian架构,而网络数据“应该”采用big-endian格式。
  2. 您处理在具有不同“endianness”的系统上创建的数据文件。
  3. 在上述任何一种情况下,您都需要对大于1个字节的所有数字进行字节交换,例如,short,int,long,double等。但是,如果您始终处理来自同一个数据的数据平台,端点问题无关紧要。

    b)根据你的问题,听起来你有一个char指针,想要将前4个字节作为int提取,然后处理任何endian问题。要进行提取,请使用:

    int n = *(reinterpret_cast<int *>(myArray)); // where myArray is your data
    

    显然,这假设myArray不是空指针;否则,这将导致崩溃,因为它取消引用指针,因此采用一种良好的防御性编程方案。

    要在Windows上交换字节,可以使用winsock2.h中定义的ntohs()/ ntohl()和/或htons()/ htonl()函数。或者您可以编写一些简单的例程来在C ++中执行此操作,例如:

    inline unsigned short swap_16bit(unsigned short us)
    {
        return (unsigned short)(((us & 0xFF00) >> 8) |
                                ((us & 0x00FF) << 8));
    }
    
    inline unsigned long swap_32bit(unsigned long ul)
    {
        return (unsigned long)(((ul & 0xFF000000) >> 24) |
                               ((ul & 0x00FF0000) >>  8) |
                               ((ul & 0x0000FF00) <<  8) |
                               ((ul & 0x000000FF) << 24));
    }
    

答案 2 :(得分:3)

取决于你想如何阅读它们,我感觉你想把4个字节转换成一个整数,这样做通过网络流数据通常会以这样的方式结束:

int foo = *(int*)(stream+offset_in_stream);

答案 3 :(得分:3)

解决这个问题的简单方法是确保以一致的字节顺序生成字节。通常,各种TCP / IP内容使用的“网络字节顺序”是 最好:图书馆例程 htonl ntohl 非常适合这个,他们 通常都是相当好的优化。

但是,如果未使用网络字节顺序,则可能需要执行操作 其他方法。您需要知道两件事:整数的大小和字节顺序。 一旦你知道了,就知道要提取多少字节以及放入哪个顺序 他们一起变成了一个int。

假设sizeof(int)的一些示例代码是正确的字节数:

#include <limits.h>

int bytes_to_int_big_endian(const char *bytes)
{
    int i;
    int result;

    result = 0;
    for (i = 0; i < sizeof(int); ++i)
        result = (result << CHAR_BIT) + bytes[i];
    return result;
}

int bytes_to_int_little_endian(const char *bytes)
{
    int i;
    int result;

    result = 0;
    for (i = 0; i < sizeof(int); ++i)
        result += bytes[i] << (i * CHAR_BIT);
    return result;
}


#ifdef TEST

#include <stdio.h>

int main(void)
{
    const int correct = 0x01020304;
    const char little[] = "\x04\x03\x02\x01";
    const char big[] = "\x01\x02\x03\x04";

    printf("correct: %0x\n", correct);
    printf("from big-endian: %0x\n", bytes_to_int_big_endian(big));
    printf("from-little-endian: %0x\n", bytes_to_int_little_endian(little));
    return 0;
}

#endif

答案 4 :(得分:3)

怎么样

int int_from_bytes(const char * bytes, _Bool reverse)
{
    if(!reverse)
        return *(int *)(void *)bytes;

    char tmp[sizeof(int)];

    for(size_t i = sizeof(tmp); i--; ++bytes)
        tmp[i] = *bytes;

    return *(int *)(void *)tmp;
}

你会这样使用它:

int i = int_from_bytes(bytes, SYSTEM_ENDIANNESS != ARRAY_ENDIANNESS);

如果您使用的系统void * int *可能导致对齐冲突,则可以使用

int int_from_bytes(const char * bytes, _Bool reverse)
{
    int tmp;

    if(reverse)
    {
        for(size_t i = sizeof(tmp); i--; ++bytes)
            ((char *)&tmp)[i] = *bytes;
    }
    else memcpy(&tmp, bytes, sizeof(tmp));

    return tmp;
}

答案 5 :(得分:1)

除非您从其他计算机上创建的源读取字节,否则您不必担心字节序。网络流。

鉴于此,你不能只使用for循环吗?

void ReadBytes(char * stream) {
    for (int i = 0; i < sizeof(int); i++) {
        char foo = stream[i];
        }
    }
 }

你要求的东西比那更复杂吗?

答案 6 :(得分:1)

只有当您正在阅读的数据由大于一个字节的数字组成时,才需要担心字节顺序。
如果您正在读取sizeof(int)字节并期望将它们解释为int,则endianess会产生影响。实质上endianness是机器将一系列超过1个字节解释为数值的方式。

答案 7 :(得分:1)

只需使用在sizeof(int)块中移动数组的for循环 使用函数ntohl(在标题<arpa/inet.h>中找到,至少在Linux上)将网络顺序中的字节(网络顺序定义为big-endian)转换为本地字节顺序。该库函数用于为您运行的任何处理器执行正确的网络到主机转换。

答案 8 :(得分:1)

为什么要在比较时阅读?

bool AreEqual(int i, char *data)
{
   return memcmp(&i, data, sizeof(int)) == 0;
}

当你需要将所有整数转换为某种不变形式时,如果你担心字节序。 htonl和ntohl是很好的例子。