代码之家  ›  专栏  ›  技术社区  ›  Some Name

关于标识符链接的混淆

  •  1
  • Some Name  · 技术社区  · 6 年前

    我在读C标准 N1570 并面临着一些关于联系的误解。如规定 6.2.2. Linkages of objects :

    5如果函数的标识符声明没有 存储类说明符,其链接与 用存储类说明符extern声明。 如果 对象的标识符声明具有文件范围,没有 存储类说明符,其链接是外部的。

    所以我猜 extern 在具有文件范围的对象的标识符声明中没有存储类说明符。

    让我们来看看下面的例子:

    test.h :

    #ifndef _TEST_H
    #define _TEST_H
    
    int a;
    
    void increment();
    
    #endif //_TEST_H
    

    test.c :

    #include "test.h"
    
    void increment(){
        a += 2;
    }
    

    main.c :

    #include <stdio.h>
    #include "test.h"
    
    int main(int argc, char const *argv[])
    {
        increment();
        printf("a = %d\n", a);
    }
    

    自从 a 声明为具有外部链接(文件范围,没有存储类说明符) a = 2 按预期打印。

    所以我取代了 拥有 外部 说明符和预期无差异(根据 6.2.2#5 以上我引用过:

    测试h :

    #ifndef _TEST_H
    #define _TEST_H
    
    extern int a; // <---- Note extern here
    
    void increment();
    
    #endif //_TEST_H
    

    但是现在链接器抱怨:

    CMakeFiles/bin.dir/main.c.o: In function `main':
    main.c:37: undefined reference to `a'
    liblibtest.a(test.c.o): In function `increment':
    test.c:4: undefined reference to `a'
    test.c:4: undefined reference to `a'
    collect2: error: ld returned 1 exit status
    

    标准如何解释这种行为?由于标识符在这两种情况下具有相同的链接,我希望链接器行为也相同。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Sourav Ghosh    6 年前

    在第一个案例中 int a 是一个 尝试性定义 .

    在第二种情况下,a 定义 对于 a 缺少,只有声明。这就是Linker抱怨的原因。

    引用 C11 ,第§6.9.2章

    具有文件作用域但没有初始值设定项的对象的标识符声明,以及 没有存储类说明符或存储类说明符 static 构成 尝试性定义 . 如果翻译单元包含一个或多个 标识符,而翻译单元不包含该标识符的外部定义,则 这种行为就好像翻译单元包含一个文件范围声明 标识符,复合类型作为转换单元的结尾,具有初始值设定项 等于0。