C语言 命名冲突与static修饰符

整理自《C陷阱与缺陷》。

1. 链接

链接器:
C源文件经过编译器生成目标文件。
链接器的输入:目标文件和库文件
链接器输出:载入模块或可执行文件

外部对象:
    连接器通常把目标模块看成是由一组外部对象组成的。每个外部对象代表着机器内存中的某个部分,并通过一个外部名称来识别。因此,程序中的每个函数和每个外部变量,如果没有被声明为static,就都是一个外部对象。某些C编译器会对静态函数和静态变量的名称做一定改变,将它们也作为外部对象。
链接器的工作:
     连接器的输入是一组目标模块和库文件。连接器的输出是一个载入模块。连接器读入目标模块和库文件,同时生成载入模块。对每个目标模块中的每个外部对象,连接器都要检查载入模块,看是否已有同名的外部对象。如果没有,连接器就将该外部对象添加到载入模块中;如果有,连接器就要开始处理命名冲突。
     除了外部对象之外,目标模块还可能包括了对其他模块中的外部对象的引用。例如:一个调用了函数printf的C程序所生成的目标模块,就包括了一个对函数printf的引用。可以推测得出,该引用指向的是一个位于某个库文件中的外部对象。在连接器生成载入模块的过程中,它必须同时记录这些外部对象的引用。当连接器读入一个目标模块时,它必须解析出这个目标模块中定义的所有外部对象的引用,并作出标记说明这些外部对象不再是未定义的。

 

2. 命名冲突与static修饰符

命名冲突:
大多数链接器都禁止同一个载入模块中的两个不同外部对象有相同的名词。 简单地说,就是不能有同名的变量或者函数。
static修饰符:
static能有效减少此类命名冲突。
static修饰的函数和变量,作用域限制在同一个源文件里,对于其他源文件不可见。
因此,如果,如果若干函数需要共享一组外部变量,可以把这些函数放到同一个源文件里,把需要用到的对象也在同一个源文件里以static修饰符声明。
例子:

static int g(int x)
{
    //函数体
}

void f()
{
    //其他内容
    b=g(a);
}

我们可以在多个文件定义同名函数g,只要所有函数都被定义为static,或者仅有一个g函数不是static。
因为了避免可能出现的同名冲突,如果一个函数仅被同一个源文件的函数调用,应该将其声明为static。

你可能感兴趣的:(C陷阱与缺陷笔记,C语言)