C 将无符号字符移位8位以上
我对这个代码有点困扰:C 将无符号字符移位8位以上,c,endianness,unsigned-char,C,Endianness,Unsigned Char,我对这个代码有点困扰: typedef struct _slink{ struct _slink* next; char type; void* data; } 假设本文描述的是文件中的链接,其中数据长度为4字节,表示地址或整数(取决于链接的类型) 现在我正在研究如何将文件中的数字从小端改为大端,所以我想做的是在写回文件之前更改字节的顺序,即。 对于0x01020304,我想把它转换成0x04030201,所以当我写回它时,它的小尾端表示看起来像0x01020304的大
typedef struct _slink{
struct _slink* next;
char type;
void* data;
}
假设本文描述的是文件中的链接,其中数据长度为4字节,表示地址或整数(取决于链接的类型)
现在我正在研究如何将文件中的数字从小端改为大端,所以我想做的是在写回文件之前更改字节的顺序,即。
对于0x01020304
,我想把它转换成0x04030201
,所以当我写回它时,它的小尾端表示看起来像0x01020304
的大尾端表示,我通过将I的第I个
字节乘以2^8*(3-I)
,其中I
在0到3之间。现在这是它的一种实现方式,这里让我感到困扰的是,它将字节移位超过8位。。(L为_slink*型)
int data=((unsigned char*)&L->data)[0]在表达式中使用时,小于int
的任何整数类型都升级为int
因此,移位实际上应用于int
类型的表达式,而不是char
类型的表达式
有人能解释一下为什么这真的有效吗
移位不是作为无符号字符发生的,而是作为升级为int
1的类型发生的
代码仍然存在问题的原因
32位int
将int
1移到符号的位置是未定义的行为。另见
对于学究来说
如果int
使用了non-2的补码,即从((unsigned char*)&L->data)[0]添加一个负值,那么实际上,代码有一个bug(无符号字符*)&L->data)[0]
是一个无符号字符
。使用8位无符号字符和32位int
,它将自动升级为int
。那么您能使用htonl
系列中的函数吗?这回答了你的问题吗?
int data = ((unsigned char*)&L->data)[0]<<24) + ((unsigned char*)&L->data)[1]<<16) +
((unsigned char*)&L->data)[2]<<8) + ((unsigned char*)&L->data)[3]<<0)
((unsigned char*)&L->data)[0]<<24) // UB
const uint8_t *p = &L->data;
uint32_t data = (uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | //
(uint32_t)p[2] << 8 | (uint32_t)p[3] << 0;