1

我可以假设 C/C++ 结构指针总是指向第一个成员吗?
示例 1:

typedef struct {
 unsigned char  array_a[2];
 unsigned char  array_b[5];
}test;
//..
test var;
//..

在上面的例子中 &var 是否总是指向 array_a?同样在上面的示例中,是否可以将指针转换为 unsigned char 指针并分别访问每个字节?
示例 2:

function((unsigned char *)&var,sizeof(test));
//...
//...
void function(unsigned char *array, int len){
 int i;
 for( i=0; i<len; i++){
    array[i]++;
 }
}

这会正常工作吗?

注意:我知道字符在结构中是字节对齐的,因此我假设上述结构的大小为 7 个字节。

4

4 回答 4

9

对于 C 结构,是的,您可以依赖它。这就是几乎所有“面向对象”风格的 API 在 C 中的工作方式(例如 GObject 和 GTK)。

对于 C++,您只能将其用于“普通旧数据”(POD)类型,这些类型保证与 C 结构一样在内存中布局。POD 类型的确切构成有点复杂,并且在 C++03 和 C++11 之间发生了变化,但关键是如果你的类型有任何虚函数,那么它就不是 POD。

(在 C++11 中,您可以std::is_pod在编译时测试结构是否是 POD 类型。)

编辑:这告诉你什么构成 C++ 中的 POD 类型:http: //en.cppreference.com/w/cpp/concept/PODType

EDIT2:实际上,在 C++11 中,它不需要是 POD,只是“标准布局”,这是一个稍微弱一点的条件。Quoth section 9.2 [class.mem] 标准的第 20 段:

指向标准布局结构对象的指针,使用 reinterpret_cast 进行适当转换,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。[注意:因此,标准布局结构对象中可能有未命名的填充,但不是在其开头,这是实现适当对齐所必需的。——尾注]

于 2013-11-05T10:06:24.923 回答
7

来自 C99 标准第 6.7.2.1 节要点 13:

在结构对象中,非位域成员和位域所在的单元的地址按声明顺序递增。一个指向结构对象的指针,经过适当的转换,指向它的初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在其开头。

因此,您的问题的答案是肯定的。

参考(参见第 103 页)

于 2013-11-05T09:55:02.657 回答
0

编译器可以自由地添加填充并重新组织它认为合适的结构。特别是在 C++ 中,您可以添加(虚拟)函数,然后很可能在此之前虚拟表被隐藏。但当然这是实现细节。对于 C,这个假设是有效的。

于 2013-11-05T09:56:13.450 回答
0

对于 C,它在很大程度上是特定于实现的,但在实践中,规则(在没有 #pragma pack 或类似的东西的情况下)是:

  • 结构成员按它们声明的顺序存储。(如前所述,这是 C99 标准所要求的。)
  • 如有必要,在每个结构成员之前添加填充,以确保正确对齐。

所以给定一个像这样的结构

struct test{
char ch;
int i;
}

将在偏移量 0 处有 ch,然后是要对齐的填充字节,在偏移量 2 处添加 i,然后在最后添加填充字节以使结构大小成为 8 字节的倍数。(在 64 位机器上,4 字节对齐在 32 位机器中可能允许)

所以至少在这种情况下,对于C,我认为你可以假设结构指针将指向第一个数组。

于 2013-11-05T09:59:58.887 回答