我试图理解结构别名是如何编译成二进制文件的,特别是当它前面有一个修饰符时。我注意到在不同的二进制文件中使用和不使用*的别名(使用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;
提前谢谢。
答案 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格式的形状。