Why is alignment on the stack for a struct with 1 member (char) handled differently than if the member was directly on the stack?

huangapple go评论64阅读模式
英文:

Why is alignment on the stack for a struct with 1 member (char) handled differently than if the member was directly on the stack?

问题

我在cpp.sh上运行了一个实验(没有特殊标志),其中字长似乎为4字节。在实验中,我在堆栈上初始化了两个类型为Data的元素,这是一个只包含一个字符的结构体,并打印出它们的地址。我对类型为char的两个变量执行了相同的操作。

#include <iostream>
#include <bitset>

struct Data {
    char c;    
};

void PrintAddr(const void* ptr) {
    std::cout << std::bitset<32>((unsigned int) ptr) << std::endl;
}

int main()
{
    std::cout << "word size = " << sizeof(size_t) << std::endl;
    std::cout << "sizeof = " << sizeof(Data) << std::endl;
    std::cout << "alignof = " << alignof(Data) << std::endl;
    
    std::cout << "Data addresses: " << std::endl;

    Data a, b;
    PrintAddr(&a);
    PrintAddr(&b);
 
    std::cout << "char addresses: " << std::endl;
 
    char c, d;
    PrintAddr(&c);
    PrintAddr(&d);
}

输出:

word size = 4
sizeof = 1
alignof = 1
Data addresses: 
00000000010100000101001011101000
00000000010100000101001011100000
char addresses: 
00000000010100000101001011011111
00000000010100000101001011011110

似乎对于类型为Data的变量a和b添加了填充,而对于类型为c和d的变量没有添加任何填充。为什么会这样呢?

英文:

I ran an experiment on cpp.sh (no special flags) where the word size seems to be 4 bytes. In my experiment, I initialized two elements of type Data, a struct with just a single char, on the stack and printed out their addresses. I did the same with two variables of type char.

#include &lt;iostream&gt;
#include &lt;bitset&gt;

struct Data {
    char c;    
};

void PrintAddr(const void* ptr) {
    std::cout &lt;&lt; std::bitset&lt;32&gt;((unsigned int) ptr) &lt;&lt; std::endl;
}

int main()
{
    std::cout &lt;&lt; &quot;word size = &quot; &lt;&lt; sizeof(size_t) &lt;&lt; std::endl;
    std::cout &lt;&lt; &quot;sizeof = &quot; &lt;&lt; sizeof(Data) &lt;&lt; std::endl;
    std::cout &lt;&lt; &quot;alignof = &quot; &lt;&lt; alignof(Data) &lt;&lt; std::endl;
    
    std::cout &lt;&lt; &quot;Data addresses: &quot; &lt;&lt; std::endl;

    Data a, b;
    PrintAddr(&amp;a);
    PrintAddr(&amp;b);
 
    std::cout &lt;&lt; &quot;char addresses: &quot; &lt;&lt; std::endl;
 
    char c, d;
    PrintAddr(&amp;c);
    PrintAddr(&amp;d);
}

Output:

word size = 4
sizeof = 1
alignof = 1
Data addresses: 
00000000010100000101001011101000
00000000010100000101001011100000
char addresses: 
00000000010100000101001011011111
00000000010100000101001011011110

It seems like padding is being added for variables a and b, of type Data, while there is none being added for type c and d. Why is this the case?

答案1

得分: 5

A pedantic answer might be that the C++ language specification gives no guarantees of what the addresses of local variables might be. They might be next to each other, or there might be padding, or they might be completely unrelated! A language-lawyer might be happy to leave it at that.

If you're asking why a specific compiler does that, you could amend your question (or add tags) to specify that.

Note that these automatic variables probably wouldn't even have addresses until you actually take their address - they'd just live in registers. Probably more so for the char variables.

So that's my guess - the compiler you use is happy to pack automatic char variables on the stack (when you take their addresses), but is reluctant to pack automatic struct variables the same way.

英文:

A pedantic answer might be that the C++ language specification gives no guarantees of what the addresses of local variables might be. They might be next to each other, or there might be padding, or they might be completely unrelated! A language-lawyer might be happy to leave it at that.

If you're asking why a specific compiler does that, you could amend your question (or add tags) to specify that.

Note that these automatic variables probably wouldn't even have addresses until you actually take their address - they'd just live in registers. Probably more so for the char variables.

So that's my guess - the compiler you use is happy to pack automatic char variables on the stack (when you take their addresses), but is reluctant to pack automatic struct variables the same way.

huangapple
  • 本文由 发表于 2023年5月22日 06:17:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76302151.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定