我gcc用以下代码发现了一个奇怪的行为:
#include <stdio.h>
#include <string.h>
int main(void)
{
const char str[] = "This string contains é which is a multi-byte character";
const char search[] = "?";
char * pos = strstr(str, search);
printf("%s\n", pos);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译器会发出警告:
$ gcc toto.c -std=c99
toto.c: In function ‘main’:
toto.c:8:18: warning: initialization discards ‘const’ qualifier
from pointer target type [enabled by default]
Run Code Online (Sandbox Code Playgroud)
但如果我改变以下内容search:
const char search[] = "é";
Run Code Online (Sandbox Code Playgroud)
同样的编译没有任何警告:为什么?
注意:如果我交换?,我有完全相同的行为é:如果字符in search不存在str,我会收到警告.
这里有几件事情正在发生.
gcc的头文件指示gcc使用其内置的,优化的strstr(),编译器知道它是什么.纯粹从语言的角度来看,strstr()只是一些库函数,理论上,编译器不知道.但是,gcc实际上知道它是什么.
gcc的优化版本strstr()如果字符串参数是a char *,则strstr()返回a char *; 但如果字符串参数是a const char *,则strstr()返回a const char *,这是有道理的.
因此,在您的情况下,strstr()返回a const char *,这会导致明显的错误,分配给非const char *.
似乎正在发生的事情是,在你的问题的第二部分,gcc找出字符串存在,并优化整个事情; 但在这种情况下,它也应该导致const char *对char *转换,并发出警告.不确定这个.
这似乎是 gcc 中的一个错误,已在以后的版本中得到纠正。
\n\n这是我写的一个小程序来说明这个问题。
\n\n#include <stdio.h>\n#include <string.h>\n\nint main(void) {\n const char message[] = "hello";\n#ifdef ASCII_ONLY\n const char search_for[] = "h";\n#else\n const char search_for[] = "\xc6\xa9";\n#endif\n char *non_const_message = strstr(message, search_for);\n if (non_const_message == NULL) {\n puts("non_const_message == NULL");\n }\n else {\n puts(non_const_message);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n当我用以下命令编译它时
\n\ngcc -DASCII_ONLY -std=c99 -pedantic-errors c.c -o c\nRun Code Online (Sandbox Code Playgroud)\n\n(在 Linux Mint 17 上使用 gcc 4.8.2),它编译时没有诊断消息,并且生成的程序打印
\n\nhello\nRun Code Online (Sandbox Code Playgroud)\n\n(我使用它-pedantic-errors是因为这会导致 gcc(尝试)成为符合 ISO C 的编译器。)
当我删除该-DASCII_ONLY选项时,我收到一条编译时错误消息:
c.c: In function \xe2\x80\x98main\xe2\x80\x99:\nc.c:11:31: error: initialization discards \xe2\x80\x98const\xe2\x80\x99 qualifier from pointer target type\n char *non_const_message = strstr(message, search_for);\nRun Code Online (Sandbox Code Playgroud)\n\n该strstr函数返回类型为 的结果char*,而不是 const char*。它需要两个const char*参数,并且使用正确的搜索字符串,它可以返回第一个参数的值。这意味着它可以默默地放弃const其论点的本质。我认为这是 C 标准库中的一个缺陷,但我们可能会坚持下去。如果一致的 C 实现想要保持一致,则无法选择“修复”此缺陷;他们可以警告危险的使用strstr,但不能拒绝其他合法代码。
strstr(这个缺陷可以通过分成两个不同名称的函数来避免,一个函数接受 aconst char*并返回 a const char*,另一个接受 achar*并返回 a char*。1989 年 ANSI C 委员会没有利用这个机会这样做,因为他们没有想到这一点,或者因为他们不想破坏现有代码。C++ 通过使用 的两个重载版本来解决这个问题strstr,而这对于 C 来说是不可能的。)
我的第一个假设是 gcc 正在“神奇地”做一些与 C++ 类似的事情——但是const仅使用 ASCII 字符丢弃的示例不会导致诊断消息。"\xc6\xa9"正如我的测试程序所示,问题是由在字符串文字(而不是)中使用非 ASCII 字符触发的"h"。
当我使用 gcc 4.9.1(我从源代码安装)而不是 gcc 4.8.2(我的系统上安装的默认版本)时,问题就消失了:
\n\n$ gcc -DASCII_ONLY -std=c99 -pedantic-errors c.c -o c && ./c\nhello\n$ gcc -std=c99 -pedantic-errors c.c -o c && ./c\nc.c: In function \xe2\x80\x98main\xe2\x80\x99:\nc.c:11:31: error: initialization discards \xe2\x80\x98const\xe2\x80\x99 qualifier from pointer target type\n char *non_const_message = strstr(message, search_for);\n ^\n$ gcc-4.9.1 -DASCII_ONLY -std=c99 -pedantic-errors c.c -o c && ./c\nhello\n$ gcc-4.9.1 -std=c99 -pedantic-errors c.c -o c && ./c\nnon_const_message == NULL\n$ \nRun Code Online (Sandbox Code Playgroud)\n\n我还没有进一步追踪该错误,但您可能可以在 4.8.2 和 4.9.1 之间修复的 gcc 错误列表中找到它
\n\n对于问题中的代码,您可以通过定义posasconst char*而不是 来避免问题char*。无论如何它应该是const char*,因为它指向一个定义为 的对象const。
| 归档时间: |
|
| 查看次数: |
1760 次 |
| 最近记录: |