我正在设计用于单元测试的微型框架,并希望能够为客户提供定义“测试套件名称”的功能。因此,我有以下名为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)如果 事先声明指定内部或外部联系, 标识符在后面的声明中的链接是 与先前声明中指定的链接相同。
我进行了一些实验:
打印以下错误消息:
error: redefinition of 'const char* const suite_name'
extern const char *const suite_name = "some suite";
工作正常,没有警告
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";
之间,我们将存在链接分歧。
答案 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
错误消息的屏幕截图