繁体   English   中英

使用指针将字节数组转换为unsigned int

[英]Convert byte array to unsigned int using pointers

char* f = (char*)malloc(4 * sizeof(char));
f[0] = 0;
f[1] = 0;
f[2] = 0;
f[3] = 1;
unsigned int j = *f;
printf("%u\n", j);

因此,如果内存看起来像这样:0000 0000 0000 0000 0000 0000 0000 0000 0001

程序输出0。如何使其输出整个32位的uint值?

因为您正在使用类型提升。 访问时, char将提升为int 您将无法对此进行诊断。 因此,您正在做的事情是取消引用char数组中的第一个元素(即0),并将其分配给一个int ...,其结果同样为0。

您想要做的是技术上未定义的行为,但通常可以。 您想这样做:

unsigned int j = *reinterpret_cast<unsigned int*>(f);

此时,您将要处理未定义的行为和平台的字节序。 您可能没有想要在字节流中记录的值。 您正在涉足需要对编译器和目标体系结构有深入了解的领域。

假设你的平台支持32位长度的整数,你可以做以下的达到你想要的那种演员

char* f = (char*)malloc(4 * sizeof(char));
f[0] = 0;
f[1] = 0;
f[2] = 0;
f[3] = 1;

uint32_t j;
memcpy(&j,f,sizeof(j));
printf("%u\n", j);

注意整数表示中的字节序。

为了确保您的代码在小端和大端系统上均可工作,您可以执行以下操作:

char f[4] = {0,0,0,1};
int32_t j = *((int32_t *)f);
j=ntohl(j);
printf("%d", j);

这将在小字节序和大字节序系统上打印1。 如果不使用ntohl,将仅在Big Endian系统上打印1。

该代码有效,因为为f分配值的方式与在Big Endian系统中相同。 由于网络顺序也是Big Endian,因此ntohl将正确转换j 如果主机是Big Endian,则j将保持不变。 如果主机是Little Endian,则j的字节将被反转。

该行发生了什么:

unsigned int j = *f; 

只是将f的第一个元素分配给整数j。 它等效于:

unsigned int j = f[0];

并且由于f [0]为0,所以实际上只是将0赋给整数:

unsigned int j = 0;

您将必须转换f的元素。

重新解释将始终导致未定义的行为。 以下示例显示了这种用法,并且始终错误的

unsigned int j = *( unsigned int* )f;

未定义的行为可能会产生任何结果,甚至是正确的结果。 即使您第一次运行该代码似乎产生正确的结果,也不能证明该程序已定义。 该程序仍未定义,并且可能随时产生不正确的结果。

没有技术上未定义的行为或通常无法运行的程序,该程序是未定义的还是未定义的。 依靠这种说法是危险和不负责任的。

幸运的是,我们不必依赖这样的错误代码。

您需要做的就是选择要存储在f中的整数的表示形式,然后将其转换。 看来您要存储在big-endian中,每个元素最多8位。 这并不意味着机器必须是高位优先的,而只是要在f中编码的整数的表示形式。 在机器上表示整数并不重要,因为此方法是完全可移植的。

这意味着最高有效字节将首先出现。 最高有效字节为f [0],最低有效字节为f [3]。

我们将需要一个能够存储至少32位的整数,并键入unsigned long来做到这一点。

char类型用于存储字符而不是整数。 应该使用无符号整数类型,例如unsigned char。

然后,仅必须进行以f编码的big-endian的转换:

unsigned char encoded[4] = { 0 , 0 , 0 , 1 };
unsigned long value = 0;
value = value | ( ( ( unsigned long )encoded[0] & 0xFF ) << 24 );
value = value | ( ( ( unsigned long )encoded[1] & 0xFF ) << 16 );
value = value | ( ( ( unsigned long )encoded[2] & 0xFF ) << 8 );
value = value | ( ( ( unsigned long )encoded[3] & 0xFF ) << 0 );

关于发布的代码:

char* f = (char*)malloc(4 * sizeof(char));
f[0] = 0;
f[1] = 0;
f[2] = 0;
f[3] = 1;
unsigned int j = *f;
printf("%u\n", j);
  1. 在C语言中, malloc()的返回类型为void* ,可以将其分配给任何其他指针,因此强制转换只会使代码混乱,并且在对代码进行维护时可能会出现问题。
  2. C标准将sizeof(char)定义为1,因此作为传递给malloc()的表达式的一部分,表达式绝对无效
  3. 一个int的大小不一定为4(以微处理器或64位体系结构为例)
  4. 函数: calloc()将所有字节预先设置为0x00
  5. 哪个字节应设置为0x01取决于基础架构的Endianness

现在让我们假设您的计算机是little Endian架构。 (即Intel或类似产品)

那么代码应类似于以下内容:

#include <stdio.h>  // printf(), perror()
#include <stdlib.h> // calloc(), exit(), EXIT_FAILURE

int main( void )
{
    char *f = calloc( 1, sizeof(unsigned int) );
    if( !f )
    {
        perror( "calloc failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, calloc successful

    // f[sizeof(unsigned int)-1] = 0x01; // if big Endian
    f[0] = 0x01;   // assume little Endian/Intel x86 or similar
    unsigned int j = *(unsigned int*)f;
    printf("%u\n", j);
}

编译/链接后,将输出以下内容:

1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM