我在 C 代码中经常使用字符串文字表。这些表或多或少都像这样:
static const char* const stateNames[STATE_AMOUNT] =
{
"Init state",
"Run state",
"Pause state",
"Error state",
};
Run Code Online (Sandbox Code Playgroud)
上面代码的问题是,如果表变长了,在开发过程中修改了,我会时不时忘记逗号。代码编译没有问题,缺少逗号,但我的程序最终崩溃,因为最后一个字符串设置为NULL. 我使用了 MinGW 和 Keil 编译器来验证。
如果缺少逗号,有没有办法为我的初始化生成编译器警告?
Dav*_*aro 63
将 each 包裹const char*在一对括号中应该可以解决问题,如以下代码段所示:
static const char* const stateNames[5] =
{
("Init state"),
("Run state"),
("Pause state") //comma missing
("Pause state3"),
("Error state")
};
Run Code Online (Sandbox Code Playgroud)
如果您忘记逗号,您将收到类似于以下内容的编译错误: error: called object is not a function or function pointer
请注意,如果您忘记了逗号,实际发生的情况是 C 实际上会连接两个(或更多)字符串,直到下一个逗号或数组末尾。例如,假设您忘记了逗号,如下所示:
static const char* const stateNames[] =
{
"Init state",
"Run state",
"Pause state" //comma missing
"Pause state3" //comma missing
"Error state"
};
int main(void)
{
printf("%s\n", stateNames[0]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这就是gcc-9.2生成的内容(其他编译器生成类似的代码):
.LC0:
.string "Init state"
.string "Run state"
.string "Pause statePause state3Error state" ; oooops look what happened
.quad .LC0
.quad .LC1
.quad .LC2
main:
push rbp
mov rbp, rsp
mov eax, OFFSET FLAT:.LC0
mov rdi, rax
call puts
mov eax, 0
pop rbp
ret
Run Code Online (Sandbox Code Playgroud)
很明显,最后三个字符串是连接在一起的,并且数组的长度不是您所期望的。
M.M*_*M.M 34
您可以让编译器对数组进行计数并在出现意外结果时生成错误消息:
enum { STATE_AMOUNT = 4 };
static const char* const stateNames[] =
{
"Init state",
"Run state",
"Pause state" // <--- missing comma
"Error state",
};
_Static_assert( sizeof stateNames / sizeof *stateNames == STATE_AMOUNT,
"oops, missed a comma" );
Run Code Online (Sandbox Code Playgroud)
_Static_assert如果您的编译器很旧并且不支持它,请参阅此线程以获取实现的想法。
作为奖励,当您添加新状态但忘记更新字符串表时,这也有帮助。但您可能也想研究 X 宏。
Moo*_*uck 11
我一直使用对显式大小数组的引用来解决这个问题。
// no explicit size here
static const char* const stateNames[] =
{
"Init state",
"Run state",
"Pause state",
"Error state",
};
static const char* const (&stateNameVerifier)[STATE_AMOUNT] = stateNames;
Run Code Online (Sandbox Code Playgroud)
http://coliru.stacked-crooked.com/a/593fc2eac80782a6
main.cpp:10:32: error: reference to type 'const char *const [5]' could not bind to an lvalue of type 'const char *const [4]'
static const char* const (&stateNameVerifier)[STATE_AMOUNT] = stateNames;
Run Code Online (Sandbox Code Playgroud)
这不会让编译器来帮助你,但我发现像下面这样写可以让人们更容易不删除逗号:
static const char* const stateNames[STATE_AMOUNT] =
{
"Init state"
, "Run state"
, "Pause state"
, "Error state"
};
Run Code Online (Sandbox Code Playgroud)