在将此问题标记为重复之前,请仔细阅读问题。
可能这是一个非常愚蠢的问题,但它一直在困扰着我。从阅读和许多其他SO问题中,我知道C语言结构体中的字段由于编译器添加的填充而不能保证是连续的。例如,根据C标准:
13 /:在结构对象内,非位域成员和位域所在的单元按其声明顺序递增地具有地址。指向结构对象的指针,在适当转换后,指向其初始成员(或者如果该成员是位域,则指向其中所包含的单元),反之亦然。结构对象中可能存在未命名的填充,但不在其开头。
我正在编写类似于Unix中的readelf和nm的程序,只是出于兴趣,需要处理特定偏移量处的字节以读取某些值。例如,在对象文件的前62个字节中包含“文件头”。文件头的0x00-0x04字节对应一个整数,而0x20-0x28字节对应一个指针等。然而,我注意到在readelf.c的原始实现中,程序员会做类似于以下这样的事情:
首先,他们声明了一个结构体(称之为ELF_H),该结构体的字段对应于文件头中的内容(即第一个字段与文件头中的前4个字节一样,第二个字段是一个字符,因为elf头中的0x04-0x05字节编码了一个字符等)。然后,他们将整个elf文件复制到内存中,并将指向该内存起始位置的指针强制转换为ELF_H类型。类似于:
在这样做之后,只需使用结构体的成员变量访问标头的每个部分。因此,他们不是使用指针算术来获取应该在0x04字节处的内容,而是使用hdr.member2(在结构体中是第二个成员,其后是一个int类型的第一个成员)。
如果结构体中的字段不能保证连续,那么这是如何工作的?
我能找到的最接近答案的是这里,但在那个例子中,结构体的成员都是相同类型的。在ELF_H中,它们是不同类型的。
提前感谢您 :)
可能这是一个非常愚蠢的问题,但它一直在困扰着我。从阅读和许多其他SO问题中,我知道C语言结构体中的字段由于编译器添加的填充而不能保证是连续的。例如,根据C标准:
13 /:在结构对象内,非位域成员和位域所在的单元按其声明顺序递增地具有地址。指向结构对象的指针,在适当转换后,指向其初始成员(或者如果该成员是位域,则指向其中所包含的单元),反之亦然。结构对象中可能存在未命名的填充,但不在其开头。
我正在编写类似于Unix中的readelf和nm的程序,只是出于兴趣,需要处理特定偏移量处的字节以读取某些值。例如,在对象文件的前62个字节中包含“文件头”。文件头的0x00-0x04字节对应一个整数,而0x20-0x28字节对应一个指针等。然而,我注意到在readelf.c的原始实现中,程序员会做类似于以下这样的事情:
首先,他们声明了一个结构体(称之为ELF_H),该结构体的字段对应于文件头中的内容(即第一个字段与文件头中的前4个字节一样,第二个字段是一个字符,因为elf头中的0x04-0x05字节编码了一个字符等)。然后,他们将整个elf文件复制到内存中,并将指向该内存起始位置的指针强制转换为ELF_H类型。类似于:
FILE *file = fopen('filename', rb);
void *start_of_file = malloc(/* size_of_file */);
fread(start_of_file, 1, /* size_of_file */,file); // copies entire file into memory
ELF_H hdr = *(ELF_H) start_of_file; // type case pointer to be of type struct and dereference
在这样做之后,只需使用结构体的成员变量访问标头的每个部分。因此,他们不是使用指针算术来获取应该在0x04字节处的内容,而是使用hdr.member2(在结构体中是第二个成员,其后是一个int类型的第一个成员)。
如果结构体中的字段不能保证连续,那么这是如何工作的?
我能找到的最接近答案的是这里,但在那个例子中,结构体的成员都是相同类型的。在ELF_H中,它们是不同类型的。
提前感谢您 :)
member1
需要填充以使member2
正确对齐,那么在分配结构时编译器为什么会知道这一点,但在访问member2
时突然不知道呢? - Tibrogargan<stddef.h>
中的offsetof()
在编译时获取结构成员的布局。这可能对你的测试很有用。 - Davislor