一些GCC编译器如何修改常量char指针?

时间:2017-05-08 15:55:45

标签: c gcc

我正在读一本名为“理解和使用C指针”的书。 在页110,它有这些行:

  

...但是,在某些编译器中,例如GCC,可以修改字符串文字。请考虑以下示例:

  char *tabheader = "Sound";
   *tabheader = 'L';
   printf("%s\n", tabheader);   //Displays "Lound"

继续描述const char *tabheader的用法,它将阻止修改此变量。

我目前正在使用Cloud 9 / Ubuntu。我使用GCC编译了这段代码并运行它。它导致segmentation fault错误,如我所料。

我对书中的这些陈述感到非常困惑。 一直以来,我对语句char *tabheader = "Sound";的理解与const char *tabHeader = "Sound";相同。现在,本书说这取决于哪个gcc编译器

我的问题是:哪个GCC编译器允许此代码运行? 你对这个有什么看法? 这也属于未定义的行为吗?

3 个答案:

答案 0 :(得分:4)

它适用于不在内存的受保护部分存储字符串文字的系统。例如,GCC的AVR端口将字符串文字存储在RAM中,并且所有RAM都是可写的,因此您可以写入它们。通常,写入字符串文字是未定义的行为,因此您不应该这样做。

你提到你对这两行之间的区别感到困惑:

char *tabheader = "Sound";
const char *tabHeader = "Sound";

主要区别在于使用const限定符,编译器在编译时知道您无法写入字符串,因此如果您尝试在运行时它将在编译时给出错误而不是未定义的行为写信给它。

答案 1 :(得分:4)

如果在编译时使用-fwritable-strings选项,这将适用于4.0之前的GCC版本。此选项已在4.0中删除。

答案 2 :(得分:1)

gcc有许多模式和兼容性。最初(20世纪70年代)在C中,没有const类型,当然也没有字符串文字不变的概念。在那些日子里,使用字符串文字作为缓冲区初始化是偶然的(但不常见)练习。

字符串文字最终和缓慢演变为隐含常数已经导致了对古代代码的维护所带来的痛苦,这取决于早期的行为。 Gcc的哲学显然使用编译器标志启用旧行为。例如,对于gcc 6.3.1 20161221(Red Hat 6.3.1-1)的man gcc-std上的部分是(部分):

  -std=
       Determine the language standard.   This option is currently only
       supported when compiling C or C++.

       The compiler can accept several base standards, such as c90 or
       c++98, and GNU dialects of those standards, such as gnu90 or
       gnu++98.  When a base standard is specified, the compiler accepts
       all programs following that standard plus those using GNU
       extensions that do not contradict it.  For example, -std=c90 turns
       off certain features of GCC that are incompatible with ISO C90,
       such as the "asm" and "typeof" keywords, but not other GNU
       extensions that do not have a meaning in ISO C90, such as omitting
       the middle term of a "?:" expression. On the other hand, when a GNU
       dialect of a standard is specified, all features supported by the
       compiler are enabled, even when those features change the meaning
       of the base standard.  As a result, some strict-conforming programs
       may be rejected.  The particular standard is used by -Wpedantic to
       identify which features are GNU extensions given that version of
       the standard. For example -std=gnu90 -Wpedantic warns about C++
       style // comments, while -std=gnu99 -Wpedantic does not.

       A value for this option must be provided; possible values are

       c90
       c89
       iso9899:1990
           Support all ISO C90 programs (certain GNU extensions that
           conflict with ISO C90 are disabled). Same as -ansi for C code.

       iso9899:199409
           ISO C90 as modified in amendment 1.

       c99
       c9x
       iso9899:1999
       iso9899:199x
           ISO C99.  This standard is substantially completely supported,
           modulo bugs and floating-point issues (mainly but not entirely
           relating to optional C99 features from Annexes F and G).  See
           <http://gcc.gnu.org/c99status.html> for more information.  The
           names c9x and iso9899:199x are deprecated.

       c11
       c1x
       iso9899:2011
           ISO C11, the 2011 revision of the ISO C standard.  This
           standard is substantially completely supported, modulo bugs,
           floating-point issues (mainly but not entirely relating to
           optional C11 features from Annexes F and G) and the optional
           Annexes K (Bounds-checking interfaces) and L (Analyzability).
           The name c1x is deprecated.

       gnu90
       gnu89
           GNU dialect of ISO C90 (including some C99 features).

       gnu99
       gnu9x
           GNU dialect of ISO C99.  The name gnu9x is deprecated.

       gnu11
       gnu1x
           GNU dialect of ISO C11.  This is the default for C code.  The
           name gnu1x is deprecated.

       c++98
       c++03
           The 1998 ISO C++ standard plus the 2003 technical corrigendum
           and some additional defect reports. Same as -ansi for C++ code.

       gnu++98
       gnu++03
           GNU dialect of -std=c++98.

       c++11
       c++0x
           The 2011 ISO C++ standard plus amendments.  The name c++0x is
           deprecated.

       gnu++11
       gnu++0x
           GNU dialect of -std=c++11.  The name gnu++0x is deprecated.

       c++14
       c++1y
           The 2014 ISO C++ standard plus amendments.  The name c++1y is
           deprecated.
...

请注意,还有其他编译器标志可以控制K&amp; R函数头和类似方面的接受或拒绝或替代处理。