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

Allowing "overriding" zero-initialized object with internal linkage

我正在为单元测试设计一个微框架,希望能够为客户提供定义 "test suite name" 的能力。所以我有以下名为 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
}

这样做的目的是让客户"override" 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

  1. https://ideone.com/:

工作完全正常,没有产生任何警告

DEMO

  1. 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

省略静态

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

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

错误信息截图