[英]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);
malloc()
的返回类型为void*
,可以将其分配给任何其他指针,因此强制转换只会使代码混乱,并且在对代码进行维护时可能会出现问题。 sizeof(char)
定义为1,因此作为传递给malloc()
的表达式的一部分,表达式绝对无效 int
的大小不一定为4(以微处理器或64位体系结构为例) calloc()
将所有字节预先设置为0x00 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.