简体   繁体   English

为什么 C 中的复合文字是可修改的

[英]Why are compound literals in C modifiable

One does usually associate 'unmodifiable' with the term literal人们通常会将“不可修改”与“文字”一词​​联系起来

char* str = "Hello World!";
*str = 'B';  // Bus Error!

However when using compound literals, I quickly discovered they are completely modifiable (and looking at the generated machine code, you see they are pushed on the stack):然而,当使用复合文字时,我很快发现它们是完全可修改的(查看生成的机器代码,您会看到它们被压入堆栈):

char* str = (char[]){"Hello World"};
*str = 'B';  // A-Okay!

I'm compiling with clang-703.0.29 .我正在编译clang-703.0.29 Shouldn't those two examples generate the exact same machine code?这两个示例不应该生成完全相同的机器代码吗? Is a compound literal really a literal, if it's modifiable?如果可以修改,复合文字真的是文字吗?

EDIT: An even shorter example would be:编辑:一个更短的例子是:

"Hello World"[0] = 'B';  // Bus Error!
(char[]){"Hello World"}[0] = 'B';  // Okay!

A compound literal is an lvalue and values of its elements are modifiable.复合文字是左值,其元素的值是可修改的。 In case of在的情况下

char* str = (char[]){"Hello World"};
*str = 'B';  // A-Okay!  

you are modifying a compound literal which is legal.您正在修改合法的复合文字。

C11-§6.5.2.5/4: C11-§6.5.2.5/4:

If the type name specifies an array of unknown size, the size is determined by the initializer list as specified in 6.7.9, and the type of the compound literal is that of the completed array type .如果类型名称指定了一个未知大小的数组,则大小由 6.7.9 中指定的初始化列表确定,复合文字的类型是完整数组类型的类型 Otherwise (when the type name specifies an object type), the type of the compound literal is that specified by the type name.否则(当类型名称指定对象类型时),复合文字的类型是由类型名称指定的类型。 In either case, the result is an lvalue .在任何一种情况下,结果都是一个 lvalue

As it can be seen that the type of compound literal is a complete array type and is lvalue, therefore it is modifiable unlike string literals可以看出复合字面量的类型是一个完整的数组类型并且是左值,因此与字符串字面量不同,它是可修改的

Standard also mention that标准还提到

§6.5.2.5/7:第 6.5.2.5/7 节:

String literals, and compound literals with const-qualified types, need not designate distinct objects.字符串文字和具有 const 限定类型的复合文字不需要指定不同的对象。 101 101

Further it says:进一步说:

11 EXAMPLE 4 A read-only compound literal can be specified through constructions like: 11 示例 4 可以通过以下结构指定只读复合文字:

 (const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}

12 EXAMPLE 5 The following three expressions have different meanings: 12 例 5 以下三个表达式具有不同的含义:

 "/tmp/fileXXXXXX" (char []){"/tmp/fileXXXXXX"} (const char []){"/tmp/fileXXXXXX"}

The first always has static storage duration and has type array of char , but need not be modifiable ;第一个始终具有静态存储持续时间并且具有char类型的数组,但不需要可修改 the last two have automatic storage duration when they occur within the body of a function, and the first of these two is modifiable .后两个在函数体内出现时具有自动存储持续时间,而这两个中第一个是可修改的

13 EXAMPLE 6 Like string literals, const-qualified compound literals can be placed into read-only memory and can even be shared. 13 示例6 像字符串文字一样,const 限定的复合文字可以放入只读存储器中,甚至可以共享。 For example,例如,

 (const char []){"abc"} == "abc"

might yield 1 if the literals' storage is shared.如果文字的存储是共享的,则可能会产生 1。

The compound literal syntax is a short hand expression equivalent to a local declaration with an initializer followed by a reference to the unnamed object thus declared:复合字面量语法是一种简写表达式,等效于带有初始值设定项的局部声明,后跟对如此声明的未命名对象的引用:

char *str = (char[]){ "Hello World" };

is equivalent to:相当于:

char __unnamed__[] = { "Hello world" };
char *str = __unnamed__;

The __unnamed__ has automatic storage and is defined as modifiable, it can be modified via the pointer str initialized to point to it. __unnamed__具有自动存储并定义为可修改的,可以通过初始化为指向它的指针str进行修改。

In the case of char *str = "Hello World!";char *str = "Hello World!"; the object pointed to by str is not supposed to be modified. str指向的对象不应被修改。 In fact attempting to modify it has undefined behavior.事实上,试图修改它有未定义的行为。

The C Standard could have defined such string literals as having type const char[] instead of char[] , but this would generate many warnings and errors in legacy code. C 标准本可以将此类字符串文字定义为具有类型const char[]而不是char[] ,但这会在遗留代码中产生许多警告和错误。

Yet it is advisable to pass a flag to the compiler to make such string literals implicitly const and make the whole project const correct, ie: defining all pointer arguments that are not used to modify their object as const .然而,建议向编译器传递一个标志,使此类字符串文字隐式为const并使整个项目const正确,即:将所有未用于修改其对象的指针参数定义为const For gcc and clang , the command line option is -Wwrite-strings .对于gccclang ,命令行选项是-Wwrite-strings I also strongly advise to enable many more warnings and make them fatal with -Wall -W -Werror .我还强烈建议启用更多警告,并使用-Wall -W -Werror使它们变得致命。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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