C 字符串文字是常量吗?

C 字符串文字是常量吗?,c,string,constants,literals,C,String,Constants,Literals,如果我给一个char*分配一个字符串文字,即使使用了很多迂腐的选项(-Wall-W-pedantic-std=c99),GCC和Clang也不会抱怨: 当然,如果我把const char*分配给char*,他们会抱怨 这是否意味着字符串文字被视为char*类型?它们不应该是常量字符*?如果他们被修改,这不是定义的行为 (一个不相关的问题)关于命令行参数(即:argv):它被认为是一个字符串文本数组吗?它们属于char[N]类型,其中N是包括终止的\0在内的字符数。因此,是的,您可以将它们分配给c

如果我给一个
char*
分配一个字符串文字,即使使用了很多迂腐的选项(
-Wall-W-pedantic-std=c99
),GCC和Clang也不会抱怨:

当然,如果我把
const char*
分配给
char*
,他们会抱怨

这是否意味着字符串文字被视为
char*
类型?它们不应该是
常量字符*
?如果他们被修改,这不是定义的行为


(一个不相关的问题)关于命令行参数(即:
argv
):它被认为是一个字符串文本数组吗?

它们属于
char[N]
类型,其中
N
是包括终止的
\0
在内的字符数。因此,是的,您可以将它们分配给
char*
,但仍然无法写入它们(效果将未定义)


Wrt
argv
:它指向指向字符串的指针数组。这些字符串是可显式修改的。您可以更改它们,并且需要它们保存最后存储的值

它们属于
char[N]
类型,其中
N
是包含终止字符的字符数
\0
。因此,是的,您可以将它们分配给
char*
,但仍然无法写入它们(效果将未定义)


Wrt
argv
:它指向指向字符串的指针数组。这些字符串是可显式修改的。您可以更改它们,并且需要它们保存最后存储的值

在C89和C99中,字符串文字的类型都是
char*
(据我所知,是出于历史原因)。您认为尝试修改一个会导致未定义的行为是正确的。GCC有一个特定的警告标志(它不是
-Wall
)的一部分,如果您试图这样做,它会警告您

对于
argv
,参数被复制到程序的地址空间中,并且可以在
main()
函数中安全地进行修改


编辑:哎呀,
-Wno写入字符串
是意外复制的。使用正确(肯定)形式的警告标志进行了更新。

在C89和C99中,字符串文字的类型为
char*
(据我所知,出于历史原因)。您认为尝试修改一个会导致未定义的行为是正确的。GCC有一个特定的警告标志(它不是
-Wall
)的一部分,如果您试图这样做,它会警告您

对于
argv
,参数被复制到程序的地址空间中,并且可以在
main()
函数中安全地进行修改


编辑:哎呀,
-Wno写入字符串
是意外复制的。使用正确(肯定)形式的警告标志进行更新。

它们是const char*,但对于const之前存在的遗留代码,将它们指定给char*有一个特定的排除。命令行参数肯定不是文字参数,它们是在运行时创建的。

它们是const char*,但对于const之前存在的遗留代码,将它们指定给char*有一个特定的排除项。而且命令行参数绝对不是文字,它们是在运行时创建的。

Johannes关于类型和内容的回答是正确的。但除此之外,是的,修改字符串文本的内容是未定义的行为

关于您关于
argv
的问题:

参数argc和argv以及 argv数组指向的字符串 应可由程序修改, 并保留其最后存储的值 在程序启动和程序运行之间 终止


关于类型和内容,约翰尼斯的回答是正确的。但除此之外,是的,修改字符串文本的内容是未定义的行为

关于您关于
argv
的问题:

参数argc和argv以及 argv数组指向的字符串 应可由程序修改, 并保留其最后存储的值 在程序启动和程序运行之间 终止


使用
-Wwrite strings
选项,您将获得:

warning: initialization discards qualifiers from pointer target type
不管该选项如何,除非使用
-fwritable strings
另有说明,否则GCC将把文本放入只读内存部分(不过,该选项已从最新的GCC版本中删除)


命令行参数不是常量,它们通常位于堆栈上。

使用
-Wwrite strings
选项,您将获得:

warning: initialization discards qualifiers from pointer target type
不管该选项如何,除非使用
-fwritable strings
另有说明,否则GCC将把文本放入只读内存部分(不过,该选项已从最新的GCC版本中删除)

命令行参数不是常量,它们通常位于堆栈上。

字符串文字具有形式类型
char[]
但语义类型
const char[]
。纯粹主义者讨厌它,但这通常是有用且无害的,除了让很多新手提出“为什么我的程序会崩溃?!?!”的问题。

字符串文字有形式类型
char[]
但语义类型
const char[]
。纯粹主义者讨厌它,但这通常是有用且无害的,除了让许多新手提出“为什么我的程序会崩溃?!?!”的问题。

为了完整起见,(C89和C11有类似的措词)在
6.4.5
字符串文字第5段中说:

[…]值为零的字节或代码被追加到由字符串文本产生的每个多字节字符序列中。然后使用多字节字符序列初始化静态存储持续时间和长度刚好足以包含序列的数组。对于字符串文字,数组元素具有类型char,并使用多字节字符序列的各个字节初始化;[……]

这是说一根线点亮了
void foo( const char  * ) { std::cout << "const char *" << std::endl; }
void foo(       char  * ) { std::cout << "      char *" << std::endl; }

int main() {
        const char arr_cc[3] = "hi";
        char arr_c[3] = "hi";

        foo(arr_cc); // const char *
        foo(arr_c);  //       char *
        foo("hi");   // const char *
}
void foo( const char  (&)[3] ) { std::cout << "const char (&)[3]" << std::endl; }
void foo(       char  (&)[3] ) { std::cout << "      char (&)[3]" << std::endl; }
template<typename T>
void bar(T *t) { // will deduce   const char   when a literal is supplied
    foo(t);
}