我们如何允许使用前向声明的对象或函数,我们怎么做不到?
如果我们在没有定义它的情况下声明一个对象或函数,我们如何允许它在声明之前使用它以及如何在声明之前不允许它使用它? (对于在定义之前使用转发的声明结构标记的类似问题,基本上我们如何允许使用不完整类型以及如何不使用,请参阅https://stackoverflow.com/a/45725061/3284469 )
如果声明出现在文件范围或块范围内,这是否重要?
如果其定义出现在相同或不同的翻译单元中,这是否重要?
例如
extern int i; (what can we do with i here?) (what can't we do with i here?) int A = i+3; // error: initializer element is not constant. This is an error not due to forward declaration of int i int i = 3; void fun(); (what can we do with fun here?) (what can't we do with fun here?) void fun(){};
声明一个对象是在其他地方提供定义的承诺。 一旦声明了函数或外部变量,从那时起,您就可以执行任何可以对您定义的函数或变量执行的操作。
声明的范围对您可以执行的操作没有任何影响,只能在代码中您可以执行此操作的位置。
在大多数情况下,代码转换器要求在链接代码时满足所有外部引用。 否则,您会收到链接错误。
此规则的一个例外是在sizeof
表达式中使用声明的对象,该对象不需要访问底层对象:
extern int undefined; size_t res = sizeof(undefined);
上面的内容不会破坏链接,因为sizeof
表达式不会生成对其参数的访问。
除了内联之外,您可以对声明执行任何操作。 例如:
void fun(); inline void fun(){}
在声明之后,您可以调用该函数,除非该定义被inline
标记,在这种情况下,它将导致链接器错误,因为该定义不会发出要链接的符号。 即使您没有明确说明inline
,如果已经看到定义,优化编译器也可以内联对函数的调用。
当你声明一个变量,一个函数,甚至一个类时,你所做的就是:有一些具有这个名字的东西,它有这种类型。 然后,编译器可以处理该名称的大多数(但不是全部)使用,而无需该名称的完整定义。 声明一个值 – 不定义它 – 允许您编写编译器可以理解的代码,而无需记录所有细节。 如果您使用多个源文件,并且需要在多个文件中使用函数,这将特别有用。 您不希望将函数体放在多个文件中,但您需要为它提供声明。
extern int i;
这里,已经声明了整数类型变量i
(但是没有定义,即到目前为止变量i
没有内存分配)。 我们可以根据需要多次进行此声明。
void fun();
函数fun()
声明,但未定义。 但它确实告诉编译器它可以使用这个函数并期望它将被定义在某个地方。
我能在这做什么呢?
同
extern int i;
-
i
可以根据程序的要求多次申报。 -
你可以有一个初始化器
extern int i = 0;
我在这里不能做什么?
如果不在程序中定义,则不能使用i
。
extern int i; int main(void) { i = 10; // Will through an error return 0; }
在函数的情况下,该关键字仅告知该函数的链接是extern
。 默认情况下,函数声明/定义的链接是extern。