2017-05-08 38 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函數頭和類似方面。