【问题标题】:Modifying non-string literals in C [duplicate]在 C 中修改非字符串文字 [重复]
【发布时间】:2020-07-14 09:09:34
【问题描述】:

众所周知,不能在 C 中修改字符串文字。spec(第 6.4.5-7 节)明确提到修改字符串文字是未定义的行为。尝试使用 GCC 执行此操作会导致段错误,因为文字存储在只读内存中。

但是,以下代码似乎可以在 GCC 中正常工作。

int main() {
  int *arr = (int[]){1,2,3};
  arr[1] = 100;
  printf("arr[1]: %i\n", arr[1]);
}

查看规范的第 6.5.2.5.-5 节,显示arr 将具有自动存储持续时间,类似于我声明int arr[] = {1,2,3}; 的情况。

字符串文字的处理方式不同有什么原因吗?

【问题讨论】:

  • 好吧,我猜在引用的字符串文字段落中说明了一个原因:“如果它们的元素具有适当的值,则未指定这些数组是否不同”。因此,如果您在多个地方使用相同的字符串文字,编译器不必创建多个副本,而是可以一遍又一遍地引用同一个(如果您被允许这样做当然不可能)修改它们)
  • char *foo = (char[]){'f', 'o', 'o', 0}; foo[2] = 'x'; /* now fox */
  • 我不明白这个问题。有什么联系?
  • @FelixG 哦!它还说const 复合文字不需要引用不同的对象。而且由于字符串文字被暗示为const...是有道理的。
  • 我认为由于历史原因,字符串文字并不意味着是 const 限定的。 const 限定符是该语言的一个较新特性(可能在标准化期间从 C++ 借用),但字符串文字自 C 早期就已经存在。

标签: c specifications


【解决方案1】:

尝试使用 GCC 执行此操作会导致段错误,因为文字会存储在只读内存中。

这通常是错误的。

一个很好的反例是 Linux kernel

它由GCC编译并存储在RAM中。阅读undefined behavior

OSDEV wiki 上,您可以找到由 GCC 编译并存储在可写 RAM 中的其他 operating system kernels 的提及。

并且使用特殊的链接器标志,您可以ask GCC 将字符串文字放入可写内存中。 2020 年几乎没有理由这样做(除非您正在编写玩具操作系统代码)。

您可以编写或修补现有的 C 编译器(例如 nwcctinycc)以将文字字符串放入某些可写数据段中。

您可能会对Frama-CClang Static analyzer等静态程序分析工具感兴趣。

字符串文字的处理方式不同有什么原因吗?

是的,编码optimizing compilers 很困难。还要注意Rice's theorem。考虑使用CompCert(您可能需要为许可证付费),或编写您的GCC plugin(它可能会将每个以a 开头的字符串存储在某个数据段中)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-04
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多