允许通过内部链接“覆盖”零初始化的对象

时间:2019-05-29 17:13:49

标签: 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)起,没有链接分歧:

  

对于在存储类别说明符extern中声明的标识符   该标识符的先前声明可见的范围,31)如果   事先声明指定内部或外部联系,   标识符在后面的声明中的链接是   与先前声明中指定的链接相同。

我进行了一些实验:

  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)(强调我的):

  

如果函数标识符的声明没有   存储类说明符,它的链接完全确定为   它是用存储类说明符extern声明的。 如果   对象标识符的声明具有文件范围并且没有   存储类说明符,其链接是外部的。

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

1 个答案:

答案 0 :(得分:2)

使用静态

您实际上可能可以使用静态而不是外部。 在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