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

时间:2016-04-17 11:55:53

标签: c c99 literals lvalue compound-literals

人们通常将“不可修改的”与术语“

”联系起来
char* str = "Hello World!";
*str = 'B';  // Bus Error!

然而,当使用复合文字时,我很快发现它们是完全可修改的(并锁定生成的机器代码,你会看到它们被推到堆栈上):

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

我正在使用clang-703.0.29进行编译。这两个例子不应该生成完全相同的机器代码吗?如果它是可修改的,复合文字真的是文字吗?

编辑:更简短的例子是:

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

2 个答案:

答案 0 :(得分:8)

复合文字是左值,其元素的值是可修改的。在

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

您正在修改合法的复合文字。

C11-§6.5.2.5/ 4:

  

如果类型名称指定了未知大小的数组,则大小由6.7.9中指定的初始化列表确定,,复合文字的类型是已完成数组类型的类型 。否则(当类型名称指定对象类型时),类型   复合文字的大小是由类型名称指定的。 在任何一种情况下,结果都是左值

可以看出复合文字的类型是一个完整的数组类型并且是左值,因此它可以修改,不像字符串文字

标准也提到

§6.5.2.5/ 7:

  

字符串文字和具有const限定类型的复合文字不需要指定不同的对象。 101

进一步说:

  

11示例4可以通过以下结构指定只读复合文字:

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

12示例5以下三个表达具有不同的含义:

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

第一个始终具有静态存储持续时间,类型数组为char,但无需修改;最后两个在函数体内发生自动存储持续时间,并且中的第一个   两个是可修改的

     

13示例6与字符串文字一样,const限定的复合文字可以放入只读内存中,甚至可以共享。例如,

(const char []){"abc"} == "abc"
     如果文字的存储是共享的,

可能会产生1。

答案 1 :(得分:0)

复合文字语法是一个简短的表达式,等效于带有初始化程序的本地声明,然后是对这样声明的未命名对象的引用:

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

等效于:

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

__unnamed__具有自动存储功能,并且定义为可修改的,可以通过初始化为指向它的指针str对其进行修改。

对于char *str = "Hello World!";str指向的对象不应该被修改。实际上,尝试修改它具有未定义的行为。

C标准本来可以将字符串文字定义为类型const char[]而不是char[],但这会在旧代码中生成许多警告和错误。

但是建议将一个标志传递给编译器以隐式地使这样的字符串文字const并使整个项目const正确,即:定义所有不用于修改其指针的指针参数。对象为const。对于gccclang,命令行选项为-Wwrite-strings。我也强烈建议启用更多警告,并使其对-Wall -W -Werror致命。

相关问题