#define和const的分配
Allocations for #define and const
假设我有一个宏
#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中,如果内容相同,则指MSG
或const 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"
, msgc
和MSG
指向相同的位置。
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 初始化或分配空字符串文字到指向 C 中的 char 的指针或指向 C++ 中 const char 的指针的原因是什么
- 如果 const 不分配内存,为什么我可以获取 const 的地址?
- 为什么通过指针编译时不能分配 const 初始化
- 在C++中,从构造函数中将字符串文本分配给成员const char*变量时会发生什么
- const_cast const 方法中的"this"将"this"分配给外部变量?
- 为什么我需要将默认引用参数定义为 const 以便为其分配一个左值?
- 如何为const char double指针(使用新的)动态分配内存
- 通过移动分配从算术运算符过载中返回const值
- 不能将 "const char*" 类型的值分配给类型 "int" 的实体
- 将const char * const参数成员分配给新值
- 隐藏的成员变量不应在仅允许const访问的基类中突变,以便保留分配运算符
- C 错误C3892:您无法分配const变量
- 不能将 "const char *" 类型的值分配给类型为 "LPSTR" 的实体
- const 类方法是否阻止在类外部分配变量?
- 重新分配到const参考
- 在同一分配语句中进行const char*的多个字符串文字
- 将整数值分配为variadic模板列表到静态const std ::数组成员
- 使用malloc()动态分配const char字符串的内存
- 分配const char *ptr数组参数?c++