外部链接和内部链接 参见 https://blog.csdn.net/xiexievv/article/details/8487373 ,非常详细!
补充1: 不完全声明
struct s;
union u;
char str[];
编译器不知道这种类型该占几个字节的存储空间!!
具有不完全类型的变量可以通过多次声明组合成一个完全类型,比如数组 str 声明两次:
char str[];
char str[10];
当编译器碰到第一个声明时,认为 str 是一个不完全类型,碰到第二个声明时 str 就组合成完全类型了,如果编译器处理到程序文件的末尾
仍然无法把 str 组合成一个完全类型,就会报错。读者可能会想,这个语法有什么用呢?为何不在第一次声明时就把 str 声明成完全类型?有些情况下这么做有一定的理由,比如第一个声明是写在头文件里的,第二个声明写在 .c 文件里,这样如果要改数组长度,只改 .c 文件就行了,头文件可以不用改。
补充2: int i;
以下:
int i;
int i;
gcc 可以编译通过:int i;
没有明确的初始化操作,属于 临时性定义(tentative definition) 可以在程序中发生多次发生,但是最后只留一个单独的实体 。
g++不能编译通过:int i;
属于 声明性定义 ,声明的同时定义了该变量,不能重复定义变量。 C++ 决不允许重复执行相同的定义或声明,例如类的定义、struct与enum所定义的自定义类型,所以C++里面有大量的条件编译语句(#if
、#ifdef
、#elif
、#else
、#ifndef
、#endif
、#define
、#undef
)。但是类型定义typedef
可以重复。
gcc:
int i1 = 1; // definition, external linkage (gcc,标准的外部链接定义)
static int i2 = 2; // definition, internal linkage
extern int i3 = 3; // definition, external linkage (gcc,不标准的外部链接定义,应该去掉extern,否则被警告)
int i4; // tentative definition, external linkage
static int i5; // tentative definition, internal linkage
int i1; // valid tentative definition, refers to previous(gcc,允许先定义后临时性定义)
int i2; // 6.2.2 renders undefined, linkage disagreement (gcc,不允许先内部链接定义,再外部链接临时性定义)
int i3; // valid tentative definition, refers to previous
int i4; // valid tentative definition, refers to previous
int i5; // 6.2.2 renders undefined, linkage disagreement(gcc,不允许先内部链接临时性定义,再外部链接临时性定义)
extern int i1; // refers to previous, whose linkage is external
extern int i2; // refers to previous, whose linkage is internal
extern int i3; // refers to previous, whose linkage is external
extern int i4; // refers to previous, whose linkage is external
extern int i5; // refers to previous, whose linkage is internal