2017-08-14 48 views
-3

字符串文字是左值,它打开门以修改字符串文字。可以修改字符串文字和非字符串非复合文字吗?

从下在果壳:

在C源代码,字面是表示固定值,其可以是整数,浮点数字,字符的令牌,或一个字符串。文字的类型取决于其价值和符号。 这里讨论的文字与C99标准中介绍的复合文字不同。复合文字是普通的可修改对象,与变量类似。

尽管C不严格禁止修改字符串文字,但您不应该尝试这样做。对于一个 东西,编译器,将字符串文字视为常量,可能会将其置于只读 内存中,在这种情况下尝试写入操作会导致错误。另一方面,如果 程序中使用了两个或多个相同的字符串文字,编译器可能会将 存储在相同的位置,以便在 访问另一个位置时修改其中一个会导致意外的结果。

  1. 第一段说:“在C语言的文字表示的固定值”。

    • 是否意味着文字(除了复合文字)不应该被修改?

    • 由于字符串文字不是复合文字,应该修改字符串文字吗?

  2. 第二段说:“C没有严格禁止 修改字符串常量”,而编译器一样。所以字符串 应该被修改?
  3. 这两段相互矛盾吗?我怎么理解他们?

  4. 是否可以修改既不是复合字面也不是字符串的文字?

谢谢。

+8

所有书籍谎言。只相信标准。 – o11c

+0

谢谢。我会牢记这一点。我认为这本书严格遵循标准,并以更容易理解的方式解释标准。 – Tim

+0

字符串文字可能会更改,但更改的结果未定义。 – BLUEPIXY

回答

8

从C标准(6.4.5字符串文本)

7这些阵列是否是不同的条件是它们的 元素具有适当的值是不确定的。 如果程序尝试 修改这样一个数组,行为是未定义的。

至于你的说法。

第二段说:“C没有严格禁止修改 字符串文字”,而编译器一样。所以应该修改字符串文字 ?

然后编译器不修改字符串文字。它们可以将相同的字符串文字存储为一个数组。

由于@ o11c在附件J(资料)可移植性问题有书面

J.5常用的扩展

1评论指出以下扩展名被广泛使用在 许多系统,但不能移植到所有的实现。包含任何可能导致严格符合 程序无效的扩展会导致实现不合格。 此类扩展的示例包括新关键字,在标准头文件中声明的额外库函数 ,或者名称为 的预定义宏不以下划线开头。

J.5.5可写字符串文字

1字符串文本是可以修改的(在这种情况下,相同的字符串 文字应表示不同的对象)(6.4.5)。

+0

谢谢。是既不是复合字面也不是字符串文字被修改的文字? – Tim

+0

@Tim由于名称“literal”意味着它是一个未修改的字面写入值。 –

+0

你的意思是说既不是复合字面也不是字符串字面的文字是不可修改的? – Tim

4

不要修改字符串文字。将它们视为char const[]。 字符串文字有效char const[](修改它们会导致未定义的行为),但由于遗留原因,它们确实是char [],这意味着编译器不会阻止您写入它们,但是如果您这样做,程序仍然不确定。

4

并且更实际地说 - 不是每个硬件平台都提供了保护只读对象存储位置的机制。它必须被定义为UB。有三种可能的选择:

  1. 文本(和常量对象更普遍)被保存在RAM,但硬件不提供内存保护机制。没有什么能写这个位置

  2. 文本(和常量对象)都保存在RAM中,但硬件确实提供了内存保护机制阻止程序员 - 你会得到段错误

  3. 只读数据存储在只读存储器(例如uC FLASH)。你可以尝试写它,但没有效果(例如ARM)。没有硬件异常引发

1
  1. 第一段说:“在C文字表示固定值”。
    • 是否意味着文字(除了复合文字)不应该被修改?

我不知道作者意图,而是从一个字符串运行期间字面所产生的阵列的修改是公然不确定,根据C11/6.4.5p7“如果程序试图修改这样的数组,行为是不确定的。“

还应当指出的是,试图修改在运行时间期间一个字面const -qualified化合物也将导致未定义的行为,其说明沿侧一些volatileC11/6.7.3p6 - 相关未定义行为。否则,它会很好地定义修改复合文字。

例如:

char *fubar = "hello world"; 
*fubar++; // SQUARELY UNDEFINED BEHAVIOUR! 

char *fubar = (char[]){"hello world"}; 
*fubar++; // This is well defined. 

字面上"goodbye galaxy""hello world"替换,在任一种片是源代码,是好的。然而,重新定义标准函数(即#define memcpy strncpy#define size_t signed char,这两种方法都是破坏某人日的好方法)是未定义的行为。

  • 由于字符串文字不是复合文字,应该修改字符串文字吗?

从一个字符串产生的数组当然应该运行期间进行修改,任何试图这样做会引发未定义的行为。

另一方面,字符串字面本身作为引用的字符序列存在,当然,这可以根据您的选择进行修改。尽管如此,你不是有责任来修改它。

第二段说编译器做的时候“C不严格禁止修改字符串文字”。所以应该修改字符串文字?

C标准没有严格禁止很多未定义的行为;它留下的行为undefined,这意味着您的程序可能表现不正常或不可移动。在良好限定C的领域,你的程序不应以任何未定义行为,包括由多线程溢流阵列const修改对象-qualified或从字符串文字所得竞态条件的阵列等。

如果你想调用未定义的行为,C会让你在脚下自拍。你可能有充足的理由这样做;也许你的程序会更优化,或者你的编译器实际上可以让你修改字符串文字(他们说,“这是一个功能,而不是一个bug”,所以给我们你的钱,“他们说,当你变得依赖他们的非标准怪癖)。请注意,某些编译器会改为表现为尝试修改未发生崩溃,或者可能会导致一些漏洞。

...还有一点,请注意,您的代码将不再符合C代码!

这两段相互矛盾吗?

由于遗漏,也许。第一段确实说明了这些值是固定的,并且值可能的第二段通过调用未定义的行为在运行时期间可以修改。

我认为作者的意图是区分源代码和运行时环境的元素。例如,他/她可以简单地通过确保明确说明文字在运行时间不应该被修改来澄清。

我该如何理解它们?

在C这种值的领域不能在运行时期间变化,因为调用未定义的行为是指所讨论的代码不再符合C代码。

也许他们试图避免解释未定义的行为,因为它可能看起来太复杂,无法解释。如果你更深入地研究这个主题,你会发现,正如预测的那样,意义大致上是这两个词的连接。

undefined:/ʌndɪfʌɪnd/ adj。不清楚或定义。 行为:/bɪheɪvjə/名词。机器或自然现象的工作方式或功能

也就是说,尝试在运行时修改由字符串文字产生的数组导致“功能不清晰”。它不需要在计算机科学领域的任何地方记录下来,即使有文档记录,文档也可能是谎言。

是否可以修改既不是复合字面也不是字符串的文字?

作为源代码中的词汇元素,提供它不会覆盖标准符号,是的。文字不是l值(即没有任何存储),例如整数常量,显然不能在运行时修改。我想可能在某些系统上试图修改函数指针指向的内存,这可能被看作是文字;这也是不确定的行为,并会导致代码不是C.

它也有可能修改许多其他类型的元素未被视为对象 C标准,如回地址在堆栈。这就是缓冲区溢出如此危险的原因!