给定示例代码:
void func( char arg)
{
char a[2];
char b[3];
char c[6];
char d[5];
char e[8];
char f[13];
std::cout << (int)&arg << std::endl;
std::cout << (int)&a << std::endl;
std::cout << (int)&b << std::endl;
std::cout << (int)&c << std::endl;
std::cout << (int)&d << std::endl;
std::cout << (int)&e << std::endl;
std::cout << (int)&f << std::endl;
}
为什么每次调用我都会得到类似的结果:
3734052
3734048
3734044
3734080
3734088
3734072
3734056
每个地址都是偶数? 为什么地址的顺序与代码中变量的顺序不同?
最佳答案
And why are the addresses not in the same order like the variables are in the code?
结构中的第一个元素保证与结构本身位于同一位置(如果它们是结构的成员),但不保证其他元素以任何顺序排列。通常,编译器会适本地对它们进行排序,以允许它使用最少的空间。对于局部变量,它们在内存中的位置完全由编译器决定。它们可能都在同一个区域(可能因为它会利用局部性),或者它们可能遍布整个 map (如果你有一个糟糕的编译器)。
With every address being an even number?
它将它们放置在单词边界上。这使得内存访问比不将它们放置在字边界上更快。例如,如果 a
被放置在一个单词的最后一个字节和另一个单词的第一个字节:
| WORD 1 | WORD 2 |
|--------|--------|--------|--------|--------|--------|--------|--------|
| a[0] | a[1] |
然后访问 a[0]
和 a[1]
将需要将 2 个单词加载到缓存中(每个缓存未命中)。通过沿着单词边界放置 a:
| WORD 1 |
|--------|--------|--------|--------|
| a[0] | a[1] |
a[0]
上的缓存未命中将导致同时加载 a[0]
和 a[1]
时间(减少不必要的内存带宽)。这利用了局部性原则。虽然语言肯定不需要它,但它是编译器完成的非常常见的优化(除非您使用预处理器指令来阻止它)。
在您的示例中(按顺序显示):
3734044 b[0]
3734045 b[1]
3734046 b[2]
3734047 -----
3734048 a[0]
3734049 a[1]
3734050 -----
3734051 -----
3734052 arg
3734053 -----
3734054 -----
3734055 -----
3734056 f[0]
3734057 f[1]
3734058 f[2]
3734059 f[3]
3734060 f[4]
3734061 f[5]
3734062 f[6]
3734063 f[7]
3734064 f[8]
3734065 f[9]
3734066 f[10]
3734067 f[11]
3734068 f[12]
3734069 -----
3734070 -----
3734071 -----
3734072 e[0]
3734073 e[1]
3734074 e[2]
3734075 e[3]
3734076 e[4]
3734077 e[5]
3734078 e[6]
3734079 e[7]
3734080 c[0]
3734081 c[1]
3734082 c[2]
3734083 c[3]
3734084 c[4]
3734085 c[5]
3734086 -----
3734087 -----
3734088 d[0]
3734089 d[1]
3734090 d[2]
3734091 d[3]
3734092 d[4]
假设没有其他数据被分配给这些空洞,那么无论您对编译器进行什么设置都会确保您的所有数组都以字边界开始。这并不是说它在数组之间添加空间(如您所见,e
和 c
之间没有空间),而是第一个元素必须位于词边界。这是特定于实现的,标准根本不需要。
关于c++ - 为什么本地类型总是得到一个偶数地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20889938/