默认情况下,项目文件中用 C 编写的函数是否可见?

Is the visibility of a function written in C across the project files by default?

我听说 in 中的函数默认称为“extern”。那么,根据这个功能范围应该在整个项目内部,不是吗?我相信没见过这个。我只是想知道默认情况下它是否真的在项目文件中可见?

文章link:https://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

它说:

”首先,我们考虑extern在函数中的使用。原来,当声明或定义函数时,extern关键字被隐式假定。当我们写.

int foo(int arg1, char arg2);

编译器将其视为:extern int foo(int arg1, char arg2);

由于 extern 关键字将函数的可见性扩展到整个程序,因此可以在整个程序的任何文件中的任何位置使用(调用)该函数,前提是这些文件包含函数的声明。 (有了函数的声明,编译器就知道函数的定义存在于其他地方,它会继续编译文件)。所以这就是关于 extern 和函数的全部内容。 “

您可以在 C11 标准草案 N1570 的“6.2.2 标识符的链接”部分找到它。

它说:

If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern.

是的,所有函数(如果没有其他修饰符)都是隐式外部函数。您可以使用 static 修饰符更改它,这使得该函数仅对写入它的文件可见。另一个非常常见的用法是 extern inline,它使内联函数对另一个文件可见,而不仅仅是它们定义的模块。

extern 修饰符的使用对于函数定义是可选的。但是,许多 C 开发人员将其用作一种风格,以向阅读源代码的人表明没有必要在同一文件中查找函数的定义。

是的,C 默认为文件范围内的新命名对象全局可见,除非它们被声明 static

请注意 extern 而不是 表示全局可见性。这意味着先前声明的可见性或(如果没有这样的先前声明)全局可见性。

extern 在 non-static 函数上可选(对新的 (C>=C11) 内联函数有一些特殊含义)但对于文件范围变量声明,有时需要区分声明和暂定定义。

示例:

void globalFunc(void);
void globalFunc(void){ }

static void fileLocalFunc(void);
void fileLocalFunc(void){ } //ok, file-local because the previous declaration was file-local

static void another_fileLocalFunc(void);
extern void another_fileLocalFunc(void){ } //extern is optional for functions

static int fileLocal_variable;
extern int fileLocal_variable; //ok, file-local, because the previous declaration was file-local

//some noncompiling stuff:
#if 0 || CONFLICTING_FUNC_DECLARATIONS0
extern void conflictingFuncDeclarations0(void);
static void conflictingFuncDeclarations0(void);
#endif
#if 0 || CONFLICTING_FUNC_DECLARATIONS1
void conflictingFuncDeclarations1(void);
static void conflictingFuncDeclarations1(void);
#endif

#if 0 || CONFLICTING_VAR_DECLARATIONS0
int conflictingVarDeclarations0;
static int conflictingVarDeclarations0;
#endif

如果您使用的是 POSIX 系统,您可以将翻译单元编译成对象 (*.o) 文件,然后在其上使用 nm 实用程序查看哪个命名它导出(或尝试导入)。