C 为什么不需要为外部函数添加“extern”?

C 为什么不需要为外部函数添加“extern”?,c,gcc,linker,C,Gcc,Linker,下面是我的代码: //main.c //I'm not using header file here,I know it is bad practice, it is just for demo purpose. int main() { func(); return 0; } 我们可以看到,上面的代码经过编译,可以通过链接器链接,但同样的事情不适用于变量: //main.c int main() { sum += 1; return 0; } 那么这段代码将无

下面是我的代码:

//main.c
//I'm not using header file here,I know it is bad practice, it is just for demo purpose.

int main()
{
   func();
   return 0;
}
我们可以看到,上面的代码经过编译,可以通过链接器链接,但同样的事情不适用于变量:

//main.c 

int main()
{
   sum += 1;
   return 0;
}
那么这段代码将无法编译,也无法链接,我们必须添加
extern int sum在main.c中的main函数之前

但是为什么我们不需要在
main.c
中添加
extern

//main.c 

extern void func(); //or `void func();` since functions are by default external
// without above line, it still compile

int main()
{
   func();
   return 0;
}
这里有点不一致吗


注意:通过说“函数默认是外部的”,我的理解是:我们可以保存一些keystokes,而无需键入
extern
,所以void func();==extern void func();,但是我们仍然需要添加
void func()在main.c中的main函数之前,不是吗

但是我们不需要为main.c中的函数添加extern作为extern void func();或void func();(因为函数是隐式加上外部前缀的)代码仍然可以编译吗


没错。默认情况下,函数是外部函数

要使函数特定于本地源文件(翻译单元),需要为它们指定
static


另一方面,变量仅在源文件中可见。如果要使某个变量在定义它的源文件之外可见,则需要
extern

有两个完全不同的主题-函数原型和链接

void foo(void);
提供编译器所需的
extern
函数原型,以了解参数的数量和类型以及返回值的类型。函数有一个外部链接-即可以由其他编译单元访问

static void foo(void);
提供
静态
功能原型。函数没有外部链接-即其他编译单元无法访问它

static void foo(void);
默认情况下,函数具有外部链接

对象(全局范围)

定义具有外部链接和类型的对象
x
。 如果您在另一个编译单元中定义了另一个
x
对象,链接器将投诉并发出错误

extern int x; 

仅声明对象
x
,而不定义它。对象
x
必须在其他编译单元中定义。

这两个程序都是不正确的,因为C99可能会被编译器拒绝。未经事先声明,不得在表达式中使用标识符

在C89中有一条规则,如果您编写了类似于函数调用的东西,并且函数名以前没有声明过,那么编译器将插入函数声明
int f()。对于使用不带括号的其他标识符,没有类似的规则

某些编译器(取决于编译器标志)即使设置为C99或更高模式,也会发出诊断,然后执行C89行为


注意:由于隐式声明是
int func(),因此程序在C89中仍会导致未定义的行为但是函数定义有
void func()
,这是不兼容的类型。

编译器不需要了解函数的任何信息,就可以生成调用函数的代码。在没有原型的情况下,它可能会生成错误的代码,但它可以生成一些东西(至少在原则上——默认情况下,标准遵从性可能会禁止它)。编译器知道平台的调用约定——它知道根据需要将函数参数放入堆栈或寄存器中。它知道写一个符号,链接器可以在以后找到并修复它,等等


但是,当您编写“sum++”时,编译器没有任何线索,缺少一个声明,无法为其生成代码。它甚至不知道“总和”是什么东西。递增浮点数所需的代码与递增整数所需的代码完全不同,也可能与递增指针所需的代码不同。编译器不需要知道“sum”在哪里——这是链接器的工作——但它需要知道它是什么,才能生成有意义的机器代码。

“我们可以看到上面的代码是编译的”你确定吗?在我看来,
func()
没有在
main.c
中的任何地方声明。在您的情况下,隐式函数声明(
int func(void)
)与实际函数(
void func(void)
)不匹配,因此您确实有未定义的行为。
int func(void)
不在您的代码中,因为它是隐式的。这就是隐含的意思。你没有显式声明它,所以编译器为你做了。正如我所说,它是隐式声明的。编译器为您创建该声明。@amjad函数和变量是两件不同的事情,没有理由期望某些任意的“一致性”函数默认为外部函数。这不是意味着我们可以保存一些密钥库而不必键入“extern”,所以
void func();==extern void func()
,但是我们仍然需要在main方法之前添加
void func()
,不是吗?@amjad,1)是的,您可以通过省略
extern
来保存击键,但使用
extern
表示这是有意的。很多人忘了使用
static
。2) C没有对象,因此它没有方法。3) 不清楚你说的最后一点是什么意思。如果您谈论的是
main
,那么它正确的返回类型是
int
<代码>无效
不正确。如果您一般谈论函数,那么
void
是必要的,因为
func(…
在grammar@ikegami我不是说main方法,我只是说为什么我们不需要在main.c?@amjad中添加
extern void func();
,再说一遍,没有“main方法”这样的东西。方法是与类关联的函数,C没有类。///因为
extern
是默认值。您永远不需要在函数上使用
extern
。但是这样做会使您的意图更清楚。变量d
int x; 
extern int x;