简体   繁体   中英

How can some GCC compilers modify a constant char pointer?

I am reading a book titled "Understanding and Using C pointers". On page 110, it had these lines:

... However, in some compilers, such as GCC, modification of the string literal is possible. Consider the following example:

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

It goes on and describe the usage of const char *tabheader which will prevent from modifying this variable.

I am currently using Cloud 9/Ubuntu. I compiled this code using GCC and ran it. It caused segmentation fault error as I expected.

I am very perplexed with these statements in the book. All this time, my understanding of the statement char *tabheader = "Sound"; is same as const char *tabHeader = "Sound"; Now, this book is saying that is dependent on which gcc compiler

My question is this: Which GCC compiler allows this code to run? What is your opinion on this? Does this also belong to undefined behavior?

This would work in versions of GCC prior to 4.0 if you use the -fwritable-strings option when compiling. This option was removed in 4.0.

It would work on systems that don't store string literals in a protected part of memory. For example, the AVR port of GCC stores string literals in RAM and all RAM is writable, so you can probably write to them. In general, writing to a string literal is undefined behavior so you should not do it.

You mentioned you were confused about the difference between these two lines:

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

The main difference is that with the const qualifier, the compiler knows at compile time that you cannot write to the string so it will give you errors at compile time instead of undefined behavior at run time if you try to write to it.

gcc has many modes and compatibilities. Originally (1970s) in C , there was no const type and certainly no concept that a string literal was constant. It was occasional (but infrequent) practice in those days to use a string literal as a buffer initialization.

The eventual and slow evolution of string literals to being implied constants has caused pain with maintenance of ancient code which depends on earlier behavior. Gcc 's philosophy apparently enables old behavior with a compiler flag. For example, from man gcc for gcc 6.3.1 20161221 (Red Hat 6.3.1-1), the section on -std is (partially):

  -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.
...

Note that there are other compiler flags which control acceptance or rejection or alternate handling of K&R function headers and similar aspects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM