指针和数组用法混淆

  • 本文关键字:用法 数组 指针 c
  • 更新时间 :
  • 英文 :


有一个来自官方Quake 2源代码的代码摘录:

unsigned        *buf;
dheader_t       header;
...
header = *(dheader_t *)buf; // #1
for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
((int *)&header)[i] = LittleLong ( ((int *)&header)[i]); // #2

有人可以尽可能详细地解释我#1和#2行到底做了什么,因为我有点困惑或更困惑......

附言

如果有帮助,以下是其余的定义:

int     LittleLong (int l) {return _LittleLong(l);}
...
typedef struct
{
int         ident;
int         version;    
lump_t      lumps[HEADER_LUMPS];
} dheader_t;

附言2

如果需要,我已经在原始的完整源代码代码上方链接。

这是一些非常脆弱的代码,你不应该写这样的代码。

它所做的是通过intint结构,然后对_LittleLong中的每个此类int执行一些操作。此函数很可能执行从大端整数到小端序的 32 位转换。这意味着您正在查看的来源可能与接收 IP 包有关。

逐步检查代码的作用:

  • for (i=0 ; i<sizeof(dheader_t)/4 ; i++)是一种草率的写法sizeof(dheader_t)/sizeof(int).即:遍历结构体intint,32 位的块。
  • (int *)&headerdheader_t*转换为int*。这实际上是由 C 中的一个特殊规则很好地定义的,该规则允许我们从指向结构的指针转换为指向其第一个成员的指针,反之亦然,第一个成员是int.
  • 但是,这样做仅针对第一个成员进行了明确定义。相反,他们采用转换后的int*并对其应用数组取消引用:((int *)&header)[i].这是 C 语言中未定义的行为,即所谓的严格混叠冲突,在某些情况下还可能导致对齐问题。坏。
  • 然后,通过此取消引用从结构中读取的int传递给LittleLong,这很可能执行大>小端转换。
  • ((int *)&header)[i] =,在这里它被写回它被抓取的地方。

更好、更安全、定义明确且可能更快的代码可能如下所示:

void endianify (dheader_t* header)
{
_Static_assert(sizeof(dheader_t)%sizeof(uint32_t)==0,
"Broken struct: dheader_t");
unsigned char* start = (unsigned char*)header;
unsigned char* end   = start + sizeof(dheader_t);

for(unsigned char* i=start; i!=end; i+=sizeof(uint32_t))
{
uint32_t tmp;
memcpy(&tmp,i,sizeof(uint32_t));
i[0]= (tmp >> 24) & 0xFF;
i[1]= (tmp >> 16) & 0xFF;
i[2]= (tmp >>  8) & 0xFF;
i[3]= (tmp >>  0) & 0xFF;
}
}

拆卸:

endianify:
mov     eax, DWORD PTR [rdi]
bswap   eax
mov     DWORD PTR [rdi], eax
mov     eax, DWORD PTR [rdi+4]
bswap   eax
mov     DWORD PTR [rdi+4], eax
mov     eax, DWORD PTR [rdi+8]
bswap   eax
mov     DWORD PTR [rdi+8], eax
mov     eax, DWORD PTR [rdi+12]
bswap   eax
mov     DWORD PTR [rdi+12], eax
mov     eax, DWORD PTR [rdi+16]
bswap   eax
mov     DWORD PTR [rdi+16], eax
ret

最新更新