结构填充

时间:2015-04-23 04:38:23

标签: c linux struct

我知道编译器会进行结构填充,因为CPU可以读取一个字(字大小取决于架构16/32/64)但我无法理解以下示例的填充行为。

struct pad 
{ 
  char ch;
};

“struct pad”的大小为1字节(但根据填充概念,我怀疑是4字节(32位架构)。

6 个答案:

答案 0 :(得分:2)

可以在任何地址边界上有效地访问char类型,因此不需要填充。

答案 1 :(得分:2)

First, it's rather a compiler, not a CPU who adds padding—however the compiler adds padding respective to the specific target CPU capabilities (mostly to its data bus width).

Padding bytes are added for efficient memory access. When CPU reads or writes a 2-byte word on an even address through a 16-bit bus the transfer can be done in one cycle. However if 2-byte data is located at an odd address, it occupies a 'lower' half of one even-addressed word and an 'upper' half of another even-addressed word in memory. CPU then must perform two bus cycles: one for each memory word occupied by your data, each time utilizing only half the bus width for actual transfer.

For a 32-bit bus a 2-byte or 4-byte piece of data can also require two cycles if it spans across the double word (4-byte) boundary. Similar effects happen on 64-bit bus. That's why the padding: a compiler adds bytes to align data to the boundaries where they can be efficiently accessed.

Padding may happen if a shorter member is followed by a longer one.

A structure containing 1-byte members only

struct BBB {
    byte  b1;
    byte  b2;
    byte  b3;
}

doesn't need any padding - each byte can be read or written in one cycle.
Similary

struct III {
    int   i1;
    int   i2;
    int   i3;
}

provided the structure is aligned to the even boundary (according to its first member requirement) all members are properly aligned, too.

struct BI {
    byte  b;
    // one byte added here
    int   i;
}

Here one byte is added so that the 2-byte int is aligned to 2-bytes boundary.

struct IB {
    int   i;
    byte  b;
    // one byte added here
}

Surprise! Why the additional byte at the end? What data needs aligning here...?
Well, suppose you declare an array:

struct IB arr[4];

Then the array data is arranged in memory like this:

int     arr[0].i
byte    arr[0].b
// byte arr[0] padding
int     arr[1].i
byte    arr[1].b
// byte arr[1] padding
int     arr[2].i
byte    arr[2].b
// byte arr[2] padding
int     arr[3].i
byte    arr[3].b
// byte arr[3] padding

Every byte member at the end of the structure got 'extendend' to two bytes, so that the int in the next array item is aligned to an even address. Without padding every second array item would have its int member misaligned.

For a 32-bit bus up to 3 bytes of padding may be used:

struct BL {
    byte  b;
    // 3 bytes added
    long  l;
}

so that 4-bytes long is placed at 4-bytes boundary.

答案 2 :(得分:0)

这里,结构实际上有1B大小,这里不需要填充。

实际的结构填充如下所示:

#include <stdio.h>
struct char_int {
        char a;
        // 3B padding here.
        int b;
};

int main() {
        struct char_int struct_a;
        struct_a.a = 0;
        struct_a.b = 12;
        printf("sizeof(struct_a):%d, &struct_a.a:0x%x, &struct_a.b:0x%x\n",
                        sizeof(struct char_int), &struct_a.a, &struct_a.b);
        return 0;
}

在我的环境中,GCC 4.9.2 RHEL AMD64 5.9。输出如下:

  sizeof(struct_a):8, &struct_a.a:0x36a41fd0, &struct_a.b:0x36a41fd4

在堆栈或堆中为上述结构分配内存时,char aint b之间将填充3个字节,因为此处字段char_int.b的地址为offset {{ 1}},而文件4只有1个字节。

答案 3 :(得分:0)

定义结构的大小为1字节,此处不使用填充。因为char占用1个字节的内存而没有其他数据类型。

struct s1
{
  char a;
  char b;
}

这会将结构大小返回为2。使用不同大小的变量时,可以更轻松,更快速地处理地址填充结构填充。

答案 4 :(得分:0)

You're confusing the concepts of memory padding with memory controller addressing (which usually does operate on words).

For various reasons C imposes standard struct alignment requirements (though these can often be overridden using compiler #pragmas). According to the standard, the struct you defined should indeed have a size of 1 byte.

When executing this code on an x86 CPU, however, the memory controller will load the 4-byte aligned word and the CPU will extract the 1-byte value for the struct. This occurs regardless of whether the struct is 4-byte aligned or not, and has no impact on performance.

答案 5 :(得分:0)

结构填充是一个棘手的概念。所以,如果你不容易理解,就不用担心。 考虑任何结构 - 如果第一个元素的大小小于结构中的下一个元素,则只需填充,在这种情况下,应对第一个元素进行结构填充。等等!!!还没结束。 如果要查找整个结构的大小,还有一个逻辑/概念要应用。即结构的最终尺寸应该可以被结构中最大尺寸的元素整除。

现在我们将以示例的方式推导出它。

struct test {  
   char a;
   char b;
   double d;
   int m;
   double dd;
   char c;
   float f;
   double ddd;
   char e;
};

现在让我们找出每个元素的大小。

char a; 1

char b; 1

double d; 8

int m; 4

double dd; 8

char c; 1

float f; 4

double ddd; 8

char e; 8

现在我们将应用结构填充。

char a; 1 (由于上述原因,无需填充)

char b; 1 + 7 (因为char比较小,填充&#39;双倍大小&#39;完成)*

double d; 8 (由于上述原因,无需填充)

int m; 4 + 4 (因为int的尺寸比double小,填充&#39; double size&#39;已完成)

double dd; 8 (由于上述原因,无需填充)

char c; 1 + 3 *(因为char与float相比尺寸较小,填充&#39; float size&#39;已完成)*

float f; 4 + 4 (因为浮动的尺寸比双倍小,填充了“双尺寸”#

double ddd; 8 (由于上述原因,无需填充)

char e; 1 (由于上述原因,无需填充)

现在,当你需要应用可被结构的最大元素整除的第二个概念时,如果你添加了所有它 54 。 这里是8,所以54 + 2 = 56,可以被8整除。

上述结构的最终尺寸为56。