5

I am confused why compiler gives

const char s[]="hello";
s[2]='t';                 // Compile Time Error

char *t = "hello";
*(t+2)='u';              // Run time Error

I guess in both case the compiler should give compile time error. Can anyone tell me particular reason for this to be this way?

4

4 回答 4

6

在第一种情况下,您正在写入 aconst并且编译器会注意到并且可以拒绝它。

在第二种情况下,t是指向非 const 的指针char,因此您可以取消引用它并写入 at *(t+2)。但是,由于t使用指向只读段的指针进行初始化,因此您在运行时会遇到分段违规。

您可以痛苦地配置链接器以将所有数据放在可写段中。这是丑陋和不标准的。

PS 一些复杂的静态分析器(可能是Frama-C)可能会在不运行程序的情况下捕获这两个错误。还可以想象扩展 GCC,例如使用MELT来添加此类检查(但这是一项不平凡的工作,可能很难获得资金支持)。

于 2013-03-11T08:05:55.927 回答
6

向后兼容性。

您不能修改 const char。这很明显。

不明显的是,字符串文字的类型实际上是指向常量字符的指针,而不是指向字符的指针。因此,第二个声明实际上具有错误的类型。然而,由于历史原因,这是支持的。


请注意,以上内容有点谎言。字符串文字实际上是char[]类型,而不是指针。

特别是,字符串文字的类型在 C89 和 C99 中是 achar[]而不是 a const char[][我认为是 C11,但不确定]。那实际上并没有错,但是数据存储在只读段中,因此尝试写入它是未定义的行为。


此外,对于它的价值,您可以使用-Wwrite-stringsgcc(g++ 已经包含它)来警告这一点。


更多信息在这里这里

于 2013-03-11T08:06:00.520 回答
3

当你这样做时:char *t = "hello";那么t是一个指向代码部分内存的指针,所以你不能改变它。因为它是只读的,所以在运行时会出现分段错误。

当你这样做时:const char s[]="hello";那么s是堆栈上的字符数组,但它是const,所以你不能改变它并且你得到一个编译错误(编译器知道它是const所以他不允许你改变它)。

const当你不想改变你的字符串时使用是好的,因为这会产生编译错误,这比运行时错误要好。

于 2013-03-11T08:09:01.993 回答
2

考虑以下一系列语句:

char *t = "hello";
char s[5];
t = s;
*(t+2)='u';

这一系列语句不会给出运行时错误,因为语句*(t+2)='u';不是无效的。它试图在您的情况下修改 const (只读)内存位置,但编译器无法知道是否会发生访问冲突。

于 2013-03-11T08:08:08.977 回答