2017-05-08 43 views
2

我正在阅读一本书“理解和使用C指针”。 在页110上,它有以下行:某些GCC编译器如何修改常量字符指针?

...但是,在某些编译器中,如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

这本书显然是错误的。这可能是可能的,但会产生未定义的行为。正如你已经证明了你自己。 –

+3

字符串文字不是不可变的。但是,更改的结果是未定义的行为。 – BLUEPIXY

+1

旧版本的GCC有一个选项“-fwritable-strings”,这将允许这样做。它在GCC 4.0中被删除。 – Barmar

回答

4

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

你提到你感到困惑的这两条线之间的区别:

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

的主要区别是,随着const预选赛中,编译器知道在编译的时候,你不能写入字符串,因此它会如果您尝试写入,则会在编译时向您提供错误,而不是在运行时发生未定义的行为。

4

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

1

gcc有许多模式和兼容性。最初(1970年代)在C中,没有const类型,当然也没有字符串字面常量的概念。在那些日子里,偶尔(但不经常)的做法是使用字符串作为缓冲区初始化。

字符串文字最终和缓慢的演变为隐含常量已经引起了古代代码维护的痛苦,这取决于先前的行为。 Gcc的哲学显然使用编译器标志可以实现旧行为。例如,来自man gcc对于GCC 6.3.1 20161221(红帽6.3.1-1),上-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 & R函数头和类似方面。