C 允许;压倒一切;具有内部链接的零初始化对象
我正在为单元测试设计一个微框架,希望能够为客户提供定义“测试套件名称”的能力。因此,我有一个名为C 允许;压倒一切;具有内部链接的零初始化对象,c,static,language-lawyer,extern,linkage,C,Static,Language Lawyer,Extern,Linkage,我正在为单元测试设计一个微框架,希望能够为客户提供定义“测试套件名称”的能力。因此,我有一个名为test\u 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 {
test\u 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
}
其目的是允许客户端“覆盖”测试套件名称,如下所示:
#include "test_suite.h"
extern const char *const test_suite_name = "suite1";
我认为这种用法的行为定义明确,因为静态常量char*const test\u suite\u name代码>构成一个暂定定义,然后extern const char*const test\u suite\u 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”代码>带有外部链接。使用静态链接
实际上,您可以使用静态而不是外部。
在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
gcc mytest2.c -o mytest2
它作为输出给出:
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 -Wall -Wpedantic -Wextra mytest.c -o mytest
gcc mytest2.c -o mytest2
错误消息的屏幕截图
您可能想看看这里的讨论:@StephanSchlecht-Nice-catch。这个问题正是关于我正在考虑的案例。可能将extern
替换为static
是一个错误workaround@StephanSchlecht但完全使用存储类说明符是UB。有没有办法在这种情况下发出警告<代码>-Wall-Wextra-pedantic
不会发出它。1。可能需要一个-xc
来告诉编译器源文件是用c.2编写的。ideone似乎没有公开编译器警告,但这确实意味着编译器不会产生警告。@StephanSchlecht是的,静态
应该可以,因为没有链接不一致。没有指定存储类编译时没有警告,即使它是UB(链接不一致)。无论如何,没有指定存储类的情况不是违反约束,因此不需要诊断消息。是的,你说得对。框架的使用者不应该忽略静态,因为由于标准,行为是未定义的,通常应该更好地避免。此处§6.2.2(7)适用:如果在翻译单元内,同一标识符同时出现在内部和外部链接中,则行为未定义。当然也有一些C编译器可以编译它而不会出现错误消息。但这对消费者来说不是个问题吗?