为什么gcc在你使用字符串初始化非const数组时不会发出警告?

3
#include <stdio.h>

void print(char *strings[]) {
  while (*strings) printf("%s\n", *strings++);
}

int main(int argc, char *argv[]) {

  char *array[] = {"Hello", "World", NULL}; // No warning?
  const char *constArray[] = {"Hello", "World", NULL};

  print(constArray); // Warning!

  //constArray[0][0] = '!'; Compile time error
  array[0][0] = '!'; // Run time error

  return 0;
}

我原本期望在char *array[] = {"Hello", "World", NULL};中会收到警告,因为这些字符串的字符是只读的,但编译器并没有对此进行警告。所以基本上编译器让我"转换"了一个const char成为char而没有警告。
当将const char传递给在print(constArray);中接收一个char的函数时,换句话说,将const char强制转换为char,编译器确实会给出警告。我原本期望编译器在两种情况下都会给出警告,或者两种情况下都不会,但其中一种情况没有警告。
我认为这个警告非常重要,可以帮助防止像array[0][0] = '!';这样的错误。那么为什么我在第一个初始化时没有得到警告呢?

即使字符串是只读的,指针也不是。它们可以在没有任何警告的情况下被更改,这是可以接受的。 - tofro
1
@tofro,是的,但那不是重点。类型为const char *的值不能赋给类型为char *的lvalue——这违反了标准的第6.5.16/1段。这里的问题部分在于“只读”是字符串字面量的一个糟糕描述,并且它与const并不等价。标准并没有说字符串字面量是只读的;它说尝试修改它们的值会产生未定义的行为。这是一个微妙但重要的区别。 - John Bollinger
2个回答

6
为什么在第一次初始化时我不会得到警告?
因为字符串字面值的类型是char数组,而不是const char数组,尽管修改这种数组的元素会产生未定义行为。这源自C语言的早期,当时还没有const。我确信它在现代C语言中的持续存在,与更改类型可能导致的不兼容性的大小和范围有关。
然而,对于单个程序而言,GCC可以帮助您。如果您开启其-Wwrite-strings选项,则它确实会将字符串字面值的类型设置为const char [length],结果就是,您提供的构造将引发警告。

1

如果C标准确实要求const限定符,编译器应该报错。看起来这是一个值得警告的有用情况。 - Theodore Norvell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接