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;