我正在读一本名为“理解和使用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编译器允许此代码运行? 你对这个有什么看法? 这也属于未定义的行为吗?
答案 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函数头和类似方面的接受或拒绝或替代处理。