了解如何编译C struct别名

时间:2017-07-15 03:00:27

标签: c compilation

我试图理解结构别名是如何编译成二进制文件的,特别是当它前面有一个修饰符时。我注意到在不同的二进制文件中使用和不使用*的别名(使用shasum检查)。例如,给定以下结构:

typedef struct __foobar {
    int a;
    int b;
} *pfoobar_t, foobar_t;

以下变量声明与C标准和编译器透视图有何不同:

const pfoobar_t my_var;
const foobar_t *my_var;
foobar_t const *my_var;

提前谢谢。

2 个答案:

答案 0 :(得分:3)

之间的区别
const pfoobar_t my_var;

const foobar_t *my_var;

是第一个声明my_var本身是const,而第二个声明my_var是指向const对象的指针。

除文件范围外,第一个不正确,因为const变量必须初始化(因为它们无法修改)。在文件范围内,变量将初始化为NULL;因为它不能被修改,所以对它的任何使用都可以用常量NULL代替。

在第二种情况下,变量本身可以被修改,因此它是未初始化的并不重要。但是,一旦指向某些struct __foobar,就不允许使用指针修改该对象。

第三个声明与第二个声明相同。第一个可以写成

 foobar_t *const my_var;

顺便说一句,以两个下划线(例如struct __foobar)开头的标识符保留供标准库(或其他实现细节)使用,不应在程序中使用。

答案 1 :(得分:1)

结构只是内存的压缩部分。例如,32位体系结构上的int a; int b;将导致8字节结构(2 x 4字节)。

未对齐的结构(例如:9个字节)是可能的,但是当分配时(例如在堆栈上),分配的存储区将被对齐(12个字节,sub $esp, 12)。

您可以看到编译器的反应不同,并且这些分配因使用const指令而显着不同:

鉴于以下结构:

typedef struct __foobar {
    int a;
    int b;
} *pfoobar_t, foobar_t;

你试试:

#include <stdio.h>

int main(){
  foobar_t var;
  const pfoobar_t my_var = &var;
  my_var->a = 3;
  printf("%d\n", my_var->a);
}

它编译并运行没有问题。现在更改以下代码:

#include <stdio.h>

int main(){
  foobar_t var;
  const foobar_t *my_var;
  my_var->a = 3;
  printf("%d\n", my_var->a);
}

它不会编译:

const.c: In function ‘main’:
const.c:13:3: error: assignment of member ‘a’ in read-only object
   my_var->a = 3;

静态对象存储在二进制文件的专用部分中,因此您的不同声明会更改ELF格式的形状。