看看这段代码:
#include <stdio.h>
#include <stdlib.h>
int byteToInt(char *bytes) {
int32_t v =
(bytes[0] ) +
(bytes[1] << 8 ) +
(bytes[2] << 16) +
(bytes[3] << 24);
return v;
}
int main() {
char b1[] = {0xec, 0x51, 0x04, 0x00};
char b2[] = {0x0c, 0x0c, 0x00, 0x00};
printf("%d\n", byteToInt(b1));
printf("%d\n", byteToInt(b2));
printf("%d\n", *(uint32_t *)b1);
printf("%d\n", *(uint32_t *)b2);
return 0;
}
{0xec, 0x51, 0x04, 0x00}
等于283116
,但当我使用byteToInt
函数时,由于某种原因,它会返回282860
。有一些字节数组会导致类似的麻烦。我意识到这个值总是误以为256.尽管如此,大多数案例都没有任何问题 - 只需看一下b2
,它就会被计算为3084
,这是正确的。铸造方法在这些情况下很有效,但我想知道所描述的问题是什么。有人可以向我解释一下吗?
答案 0 :(得分:4)
或许char
是签名类型(由实现定义),(int)(char)(0xec)
为-20
,而(int)(unsigned char)(0xec)
为236
。
尝试使用unsigned char
和uint32_t
。
uint32_t byteToInt(unsigned char *bytes) {
uint32_t v =
((uint32_t)bytes[0]) +
((uint32_t)bytes[1] << 8) +
((uint32_t)bytes[2] << 16) +
((uint32_t)bytes[3] << 24);
return v;
}
int main() {
unsigned char b1[] = { 0xec, 0x51, 0x04, 0x00 };
unsigned char b2[] = { 0x0c, 0x0c, 0x00, 0x00 };
printf("%u\n", byteToInt(b1)); // 'u' for unsigned
printf("%u\n", byteToInt(b2));
//printf("%u\n", *(uint32_t *)b1); // undefined behavior
//printf("%u\n", *(uint32_t *)b2); // ditto
return 0;
}
请注意,在最后两个printf
中重新解释内存内容是未定义的行为(尽管通常在实践中有效)。
顺便说一句,根据标准,未定义有符号的负值:
E1 << E2
的结果是E1
左移E2
位位置; ... 如果E1
已签名 类型和非负值,E1 × 2
E2
在结果类型中可表示,那么 结果价值;否则,行为未定义。
答案 1 :(得分:0)
此代码存在一些潜在问题。第一个是编译器依赖于char类型是8位,16位还是32位。当您对字符类型执行移位操作时,它可能会丢失位而不是#34;价值。
在移动它们并添加它们之前,首先将值转换为32位类型更安全。例如:
unsigned long v =
((unsigned long)bytes[0] ) +
((unsigned long)bytes[1] << 8 ) +
((unsigned long)bytes[2] << 16) +
((unsigned long)bytes[3] << 24);
您对int32_t的使用也依赖于编译器。如果内存服务,那就是特定于Windows的int重新分类。 &#34; INT&#34;本身是编译器相关的,较旧的编译器可能将其作为16位值,因为标准表示它应该是您正在处理的机器上的单词大小。使用&#34; long&#34;而不是&#34; int&#34;保证32位值。
另外,我使用&#34; unsigned long&#34;在这个例子中,因为在这种情况下,我不认为你想要处理负数。在二进制表示中,负数具有最高位集(0x8000000)。
如果你想使用负数,那么类型应该是&#34; long&#34;相反,虽然这会在将正值字节添加到负值最大字节时打开不同的蠕虫。在你想要处理负数的情况下,你应该做一个完全不同的转换,剥离高字节的高位,进行加法,然后,如果设置了高位,则使值为负(v = -v;),然后你需要减去1,因为负数的表示(这可能超出了这个问题的范围。)
修改后的代码将是:
#include <stdio.h>
#include <stdlib.h>
unsigned long byteToInt(char *bytes) {
unsigned long v =
((unsigned long)bytes[0] ) +
((unsigned long)bytes[1] << 8 ) +
((unsigned long)bytes[2] << 16) +
((unsigned long)bytes[3] << 24);
return v;
}
int main() {
char b1[] = {0xec, 0x51, 0x04, 0x00};
char b2[] = {0x0c, 0x0c, 0x00, 0x00};
printf("%d\n", byteToInt(b1));
printf("%d\n", byteToInt(b2));
printf("%d\n", *(unsigned long *)b1);
printf("%d\n", *(unsigned long *)b2);
return 0;
}