1

说我有一个宏

#define MSG "Input your first name"

和一个常量

const char* const msg = "Input your last name" 或者 const std::string msg = "Input your last name"

在同一个程序中。

现在,msg字符串文字将有一个内存位置,程序中的每个引用都会引用该内存位置msg

但是这是否同样适用于MSG,即每次出现是否MSG引用相同的字符串文字或实际上为每次出现创建不同的字符串文字?

我的猜测是,由于宏是由预处理器处理的,因此可能会创建重复的字符串文字(不是 100% 肯定)。真的吗?我敢肯定,如果它是整数类型,重复性将无关紧要。

我的问题是特定于内存中的存储,但也欢迎其他方面。

换句话说,假设我使用msg了 100 次,但使用的内存是恒定的,但是如果使用 100 次,内存使用是恒定的还是 100MSG次?

4

6 回答 6

4

如果字符串在二进制文件中重复 100 次,那么内存中二进制文件的大小会更大——但不会影响已用堆的数量。

至于字符串是否会使用#define 重复 100 次?是的,它肯定会,如果您查看源代码的预处理器输出,您会看到这一点。然而,一些编译器可能会在稍后的步骤中删除重复项(我会假设链接)。此功能称为字符串池,MSVC 参考在这里:

http://msdn.microsoft.com/en-us/library/s0s0asdt(v=vs.110).aspx

于 2013-05-09T10:44:16.487 回答
3

宏在预处理器出现的每个地方都会被其实际内容替换。因此,当编译器获取您的代码时,您MSG将在每次发生时都被实际字符串替换,这意味着该字符串将在您的代码库中进行硬编码。

然后编译器对同一字符串的多次出现执行的操作取决于编译器设置等,但可能会将其存储一次,然后在任何出现的地方引用它。

于 2013-05-09T10:36:26.877 回答
1

代码中使用宏的每个位置都将包含预处理后MSG的文字。"Input your first name"但是,此文本是在二进制文件中出现几次还是只出现一次完全取决于您的编译器。报价[lex.string]§12

是否所有字符串文字都是不同的(即,存储在不重叠的对象中)是实现定义的。尝试修改字符串文字的效果是未定义的。

换句话说,编译器(和/或链接器)可以自由地将文本数据放入二进制映像中一次,并且代码中所有出现的文字都引用相同的数据。

于 2013-05-09T10:53:26.270 回答
1
But does the same apply to MSG, i.e., does every occurrence of MSG refer to same string literal 

这个问题没有意义,因为 MSG 没有“参考”任何东西。预处理器只是简单地进行令牌替换......在您输入 MSG 的地方,就好像您输入了“输入您的名字”一样。所以使用什么内存取决于你在哪里输入;例如,

char* a = MSG;
char* b = MSG;
char* c = "Input your first name";

生成字符串的一个副本(在使用字符串池的典型实现中,但标准不需要它),但是

char a[] = MSG;
char b[] = MSG;
char c[] = "Input your first name";

生成字符串的三个副本。(虽然,根据您使用它们的具体方式,编译器可能会将它们优化为一两个副本,甚至没有副本。)

此外,考虑

char* twice = MSG MSG;

它分配了一个包含两个 MSG 副本的字符串。我认为这最清楚地表明,味精“指”某物的概念是一种误解……您的问题将两个完全不同的问题混为一谈,宏扩展和字符串假脱机。

于 2013-05-09T11:02:57.823 回答
0

我的猜测是,由于宏是由预处理器处理的,因此可能会创建重复的字符串文字

它们可能,但实际上,几乎每个现代编译器都会将相同的字符串文字合并为一个,以便每个不同的实例"foo"确实具有相同的内存地址。但是,这通常可以通过优化编译器来完成:不要依赖它。

于 2013-05-09T10:36:17.407 回答
0

linux中的g++,如果内容相同,则为MSG或a指代相同的位置const char *

鉴于:

#include <stdio.h>

#define MSG "Input your last name"

int main()
{
    const char* const msgc = "Input your last name";

    printf("MACRO %p\n", &MSG);
    printf("char %p\n", msgc);
    printf("MACRO %p\n", &MSG);
}

以上拆解

(gdb) disassemble main
Dump of assembler code for function main():
   0x000000000040070c <+0>:     push   rbp
   0x000000000040070d <+1>:     mov    rbp,rsp
   0x0000000000400710 <+4>:     sub    rsp,0x10
   0x0000000000400714 <+8>:     mov    QWORD PTR [rbp-0x8],0x400864
   0x000000000040071c <+16>:    mov    esi,0x400864
   0x0000000000400721 <+21>:    mov    edi,0x400879
   0x0000000000400726 <+26>:    mov    eax,0x0
   0x000000000040072b <+31>:    call   0x4005c0 <printf@plt>
   0x0000000000400730 <+36>:    mov    esi,0x400864
   0x0000000000400735 <+41>:    mov    edi,0x400883
   0x000000000040073a <+46>:    mov    eax,0x0
   0x000000000040073f <+51>:    call   0x4005c0 <printf@plt>
   0x0000000000400744 <+56>:    mov    esi,0x400864
   0x0000000000400749 <+61>:    mov    edi,0x400879
   0x000000000040074e <+66>:    mov    eax,0x0
   0x0000000000400753 <+71>:    call   0x4005c0 <printf@plt>
   0x0000000000400758 <+76>:    mov    eax,0x0
   0x000000000040075d <+81>:    leave  
   0x000000000040075e <+82>:    ret    
End of assembler dump.

0x400864在这种情况下是"Input your last name"msgcMSG指向相同的位置。

于 2013-05-09T11:32:45.000 回答