#define和const的分配

Allocations for #define and const

本文关键字:分配 const #define      更新时间:2023-10-16

假设我有一个宏

#define MSG "Input your first name"

和const

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

在同一个程序中。

现在,msg字符串字面值将有一个内存位置,该位置将被程序中每次引用msg所引用。

但是同样适用于MSG,即,MSG的每次出现是指相同的字符串字面量还是实际上为每次出现创建不同的字符串字面量?

我的猜测是,由于宏是由预处理器处理的,可能会创建重复的字符串字面量(不是100%确定)。这是真的吗?我敢肯定,如果是整型的话,重复性就无关紧要了。

我的问题是专门针对内存中的存储,但其他方面也欢迎。

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

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

如果字符串将使用#define重复100次?是的,它当然会,如果你查看源的预处理器输出,你会看到这个。然而,一些编译器可能会在后面的步骤中删除重复项(我假设是链接)。这个特性被称为字符串池,MSVC参考在这里:

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

预处理器在宏出现的每个地方都用它的实际内容替换。因此,当编译器到达您的代码时,您的MSG每次出现时都将被实际字符串替换,这意味着该字符串将在您的代码库中硬编码。

编译器对同一字符串的多次出现所做的事情取决于编译器的设置等,但可能会存储一次,然后在它出现的任何地方引用它。

But does the same apply to MSG, i.e., does every occurrence of MSG refer to same string literal 

这个问题没有意义,因为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副本的字符串。我认为这最清楚地表明,味精"指的是"某种东西的概念是一种误解……你的问题合并了两个完全不同的问题,宏扩展和字符串假脱机。

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

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

换句话说,编译器(和/或链接器)可以自由地将文本数据放入二进制图像中一次,并使代码中所有文本的外观都指向相同的数据。

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

它们可能会,但在实践中,几乎每个现代编译器都会将相同的字符串字量合并为一个,因此"foo"的每个不同实例确实具有相同的内存地址。但是,无论如何,这可以通过优化编译器来完成:不要依赖它。

g++在linux中,如果内容相同,则指MSGconst char *的相同位置

给定

:

#include <stdio.h>
#define MSG "Input your last name"
int main()
{
    const char* const msgc = "Input your last name";
    printf("MACRO %pn", &MSG);
    printf("char %pn", msgc);
    printf("MACRO %pn", &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指向相同的位置。