c - 当我将字符串文字分配给非常量指针时,为什么我的 C 编译器不发出警告?
问题描述
例如,使用 Xcode 11.3.1 中的默认设置,以下代码可以正常编译:
#include <stdio.h>
int main(int argc, const char * argv[]) {
char* thing = "123";
thing[2] = '4';
printf("%s\n", thing);
return 0;
}
但是,在运行时,代码会在 EXC_BAD_ACCESS 上捕获thing[2] = '4'
。我认为这是因为代表字节的内存"123"
被编译到我的程序的二进制文件中,在现代处理器/操作系统上被标记为code 而不是 data。(这个答案证实了 - 更不用说leaq 0x4d(%rip), %rsi ; "123"
反汇编中有一行,将指针传递给相对于指令指针的地址!)
从自修改代码时代开始,C 允许这样做只是一个历史产物吗?我注意到我也可以void* x = main;
毫无怨言地分配我正在丢弃修饰符。
这个答案说:
根据 C99 的基本原理,委员会中有些人希望字符串文字是可修改的,因此标准没有明确禁止它。
有没有我可以阅读的进一步讨论?更实际的是,有没有办法告诉 clang 和/或 gcc 在不编译为 C++的情况下用警告标记此类分配(即使它们实际上并未被禁止) ?
解决方案
您引用的答案是没有引用的观点,坦率地说是胡说八道。它只不过是不破坏大量现有的遗留 C 代码,而这些代码希望在现代编译器中保持可编译性。
但是,如果您设置了必要的警告级别或选项,许多编译器会发出警告。例如在GCC中:
-Wwrite-strings
编译 C 时,为字符串常量指定类型
const char[length]
,以便将 1 的地址复制到非常量char*
指针中会产生警告。这些警告可帮助您在编译时找到可以尝试写入字符串常量的代码,但前提是您必须非常小心地const
在声明和原型中使用。否则,这只是一个麻烦。这就是我们没有-Wall
提出这些警告的原因。编译 C++ 时,警告从字符串文字到 char * 的不推荐转换。C++ 程序默认启用此警告。
CLANG 也有-Wwrite-strings
, where 的同义词是-Wwriteable-strings
-Wwritable-strings
默认情况下启用此诊断。
还控制
-Wdeprecated-writable-strings
。诊断文本:
warning: ISO C++11 does not allow conversion from string literal to A
C 编译的诊断文本不同 - 我只是引用手册。
在 GCC 中-Wwrite-strings
:
int main()
{
char* x = "hello" ;
return 0;
}
产生:
main.c:3:15: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
铿锵生产:
source_file.c:3:15: warning: initializing 'char *' with an expression of type 'const char [6]' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
推荐阅读
- python - 为什么我进入 Z1 2 列而不是 3 列以及如何使用 hotEncoder 修复它
- java - 从对象实例访问嵌套的静态枚举方法
- r - 如何在 bookdown 中启用 LaTeX shell-escape
- python - 使用自定义分隔符读取文件
- facebook - Facebook Web OAuth URL 登录被阻止,因为 URL 未列入白名单
- ios - 在 azure devops 中使用 xcode 任务的 ios ci/cd 问题
- python - 为什么乌龟不能与 pynput 一起工作,我该如何解决?
- ios - iOS Swift 5 无法在自定义视图中禁用按钮
- node.js - API网关针对不同端点的不同身份验证机制
- python - 如果它是python中的逗号,如何删除第一个字符