c - 允许 "overriding"具有内部链接的零初始化对象

标签 c static language-lawyer extern linkage

我正在设计一个用于单元测试的微框架,并希望能够为客户提供定义“测试套件名称”的能力。所以我有以下名为 test_suite.h 的头文件:

static const char *const test_suite_name;

static inline void run_all_tests(void){
    printf("Running ");
    if(!test_suite_name){
        printf("unnamed suite");
    } else {
        printf("%s suite", test_suite_name);
    }
    //run tests
}

这样做的目的是允许客户端“覆盖”test_suite_name,如下所示:

#include "test_suite.h"

extern const char *const test_suite_name = "suite1";

我认为这种用法的行为是明确定义的,因为static const char *const test_suite_name;构成了一个暂定定义,然后extern const char *const test_suite_name = "suite1"; 构成外部定义。自 6.2.2(p4) 起不存在链接分歧:

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,31) if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration.

我进行了一些实验:

  1. https://coliru.stacked-crooked.com :

打印以下错误消息:

error: redefinition of 'const char* const suite_name'
 extern const char *const suite_name = "some suite";

DEMO

  • https://ideone.com/ :
  • 工作完全正常,没有产生任何警告

    DEMO

  • gcc7.4.0 在我的机器上。
  • 产生警告:

    warning: ‘test_suite_name’ initialized and declared ‘extern’
    

    问题:上面显示的代码的行为定义明确吗?

    我很确定如果编写以下内容,行为将是未定义的:

    #include "test_suite.h"
    
    const char *const test_suite_name = "suite1"; //without extern
    

    因为6.2.2(p5)(强调我的):

    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. If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

    因此,我们在具有内部链接的 static const char *const test_suite_name; 和具有外部链接的 const char *const test_suite_name = "suite1"; 之间存在链接分歧。

    最佳答案

    静态的使用

    您实际上可以使用静态而不是外部。 Ubuntu下用gcc快速测试一下:

    #include "test_suite.h"
    
    static const char *const test_suite_name = "huhu";
    
    int main() {
          run_all_tests();
          return 0;
    }
    

    如果我编译:

    gcc -Wall -Wpedantic -Wextra mytest.c -o mytest
    

    它给出输出:

    Running huhu suite
    

    省略静态

    如果您不小心忘记指定 static,那么它应该会给出编译时错误。因此,如果我将此行更改为:

    const char *const test_suite_name = "huhu";
    

    并尝试像这样编译它:

    gcc -Wall -Wpedantic -Wextra mytest2.c -o mytest2
    

    将显示此错误消息:

    mytest2.c:3:19: error: non-static declaration of ‘test_suite_name’ follows static declaration
     const char *const test_suite_name = "huhu";
                       ^~~~~~~~~~~~~~~
    In file included from mytest2.c:1:
    test_suite.h:3:26: note: previous declaration of ‘test_suite_name’ was here
     static const char *const test_suite_name;
    

    由于这是一个错误,如果您使用以下命令进行编译,它也会输出:

    gcc mytest2.c -o mytest2
    

    错误消息屏幕截图

    Screenshot with Error Message

    关于c - 允许 "overriding"具有内部链接的零初始化对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56365581/

    相关文章:

    c++ - 在 C++ 中将矩阵高效分解为方形子矩阵

    java - 为什么在构建器设计模式中使用嵌套类,为什么不能使用setter在同一个类中构建对象

    c++ - 当参数按值传递时抛出异常

    GTK+ 的 C 编码(简单案例)

    c++ - 你如何获得你的系统在 c/c++ 中使用的编码类型?

    c - (Linux) 从 PID 为 :VID 的附加 USB 设备获取/dev/input/eventX

    java - 静态配置对象的 Spring Autowiring 失败

    Java 类和静态 block

    c - 这是在 C 中做标记指针的可移植方法吗?

    java - 合并 int[] 和 String[] 应该产生 Object[]