struct A
{
uint32_t var1;
uint32_t var2;
uint32_t var3;
uint32_t var4;
uint32_t var5;
};
在上é¢çš„结构ä¸ï¼Œç¼–译器ä¸ä¼šå¡«å……并分é…20个å—节。
现在我们有å¦ä¸€ä¸ªç»“构,其ä¸åŒ…å«ä¸€ä¸ª8å—节å˜é‡è€Œä¸æ˜¯ä¸¤ä¸ª4å—节。在这ç§æƒ…况下,编译器填充并为æ¤ç»“构分é…24个å—节。
struct B
{
uint32_t var1;
uint32_t var2;
uint32_t var3;
uint64_t var5;
};
为什么会出现这ç§è¡Œä¸ºï¼Ÿ 如果编译器将数æ®å¯¹é½åˆ°8å—节边界,那么第一个结构ä¸åº”该有4个å—节的填充 在这ç§æƒ…况下ä¸å¡«å……第二结构。如果编译器将数æ®å¯¹é½åˆ°4å—节边界,那么为什么在第二个结构ä¸æœ‰4个å—节的填充?
编译器:GCC å¹³å°ï¼š64ä½linux,x86_64
ç”案 0 :(得分:7)
对é½è§„则(在x86å’Œx86_64上)通常用于对é½å˜é‡å¤§å°ã€‚
æ¢å¥è¯è¯´ï¼Œ32ä½å˜é‡åœ¨4个å—节上对é½ï¼Œ8ä½å—节上的64ä½å˜é‡ç‰ç‰ã€‚
在第二ç§æƒ…况下,在
ä¹‹é—´æ·»åŠ äº†4个å—节的填充uint32_t var3;
uint64_t var5;
让var5
在8个å—节上对é½ã€‚
ç”±äºŽè¿™ä¸ªåŽŸå› ï¼Œæœ€å¥½ä»Žå¤§åˆ°å°è®¢è´æ•°æ®æˆå‘˜ï¼ˆä½†ç”±äºŽæ•°æ®ä½ç½®ï¼Œå¯è¯»æ€§ç‰åŽŸå› ,这并ä¸æ˜¯é‚£ä¹ˆç®€å•ã€‚)
ç”案 1 :(得分:1)
首先,结构对é½ä¸æ˜¯ä¸€é—¨ç²¾ç¡®çš„科å¦ï¼Œå¯èƒ½ä¾èµ–于架构和编译器。
在许多情况下,所有结构æˆå‘˜éƒ½æ ¹æ®æœ€å¤§å˜é‡ï¼ˆä»¥å—节为å•ä½ï¼‰å¡«å……。在您的第一个结构上,所有å˜é‡éƒ½æ˜¯uint32_t
,长度为4个å—节。然åŽï¼Œæ‚¨çš„结构大å°ç‰äºŽsizeof(uint32_t) * 5
= 4 * 5
= 20
。
åœ¨ä½ çš„ç¬¬äºŒä¸ªç»“æž„ä¸Šï¼Œæœ€å¤§çš„å…ƒç´ æ˜¯uint64_t
,其大å°ä¸º8个å—èŠ‚ã€‚æ‰€ä»¥æ‰€æœ‰å…ƒç´ éƒ½å°†æŒ‰8个å—节填充。
å‰ä¸¤ä¸ªuint32_t
被填充在一起,但第三个ä¸èƒ½æ£ç¡®å¡«å……:如果用下一个整数填充,uint64_t
将被分æˆä¸¤ä¸ªï¼å› æ¤ï¼Œç¼–译器决定让它uint32_t
自己使用,以é¿å…拆分uint64_t
。
以下是您的结构示例以åŠæ‰€æœ‰å˜é‡çš„地å€ï¼š
struct A
{
uint32_t var1; /* ..00 */
uint32_t var2; /* ..04 */
uint32_t var3; /* ..08 */
uint32_t var4; /* ..12 */
uint32_t var5; /* ..16 */
};
struct B
{
uint32_t var1; /* ..00 */
uint32_t var2; /* ..04 */
uint32_t var3; /* ..08 */
uint64_t var5; /* ..16 */
};
ç”案 2 :(得分:1)
#include <stdio.h>
typedef struct __atribute__((packed)) A {
uint32_t var1;
uint32_t var2;
uint32_t var3;
uint32_t var4;
uint32_t var5;
} A ;
typedef struct __atribute__((packed)) B {
uint32_t var1;
uint32_t var2;
uint32_t var3;
uint64_t var4;
} B;
int main()
{
printf("sizeof(A): {%d} sizeof(B): {%d}", sizeof(A), sizeof(B));
return 0;
}
试试这个,它对我有用
ç”案 3 :(得分:0)
虽然编译器å¯ä»¥æ ¹æ®éœ€è¦è‡ªç”±å¡«å……或ä¸å¡«å……,但通常它们会将å˜é‡å¯¹é½åœ¨å¯å˜å¤§å°çš„å€æ•°çš„边界上。
在struct
çš„æƒ…å†µä¸‹ï¼Œå¡«å……åŸºäºŽæœ€å¤§åŽŸå§‹å…ƒç´ çš„å¤§å°ã€‚对于第二个struct B
,var5
类型为uint64_t
。
带有éšå¼å¡«å……çš„struct B
布局如下:
struct B
{
uint32_t var1; // offset 0
uint32_t var2; // offset 4
uint32_t var3; // offset 8
uint32_t padding; // offset 12
uint64_t var5; // offset 16
};
如果var5
紧跟var3
,它将在å—节å移12处,这ä¸æ˜¯8çš„å€æ•°ã€‚å› æ¤var3
之åŽéœ€è¦æœ‰4个å—节的填充å…许var5
æ£ç¡®å¯¹é½ã€‚
在struct A
的情况下,所有å—段的大å°éƒ½æ˜¯4个å—èŠ‚ï¼Œå› æ¤ä¸éœ€è¦å¡«å……。如果您创建了æ¤ç±»åž‹çš„数组,例如struct A a[5]
,a[1]
将在a[0]
之åŽä¸º20个å—节,a[2]
将在a[1]
之åŽä¸º20个å—节,并且ç‰ç‰ã€‚å‘struct A
æ·»åŠ å¡«å……ä¼šæµªè´¹ç©ºé—´ï¼Œå› ä¸ºæ‰€æœ‰åå—段ä»ç„¶åœ¨æ‰€éœ€çš„4å—节边界上对é½ã€‚
ç”案 4 :(得分:0)
struct B
ä¸çš„å¡«å……å‡ ä¹Žè‚¯å®šä¸åœ¨æœ€åŽï¼Œä½†åœ¨ç¬¬ä¸‰ä¸ª32ä½æˆå‘˜ä¹‹åŽï¼š
struct B
{
uint32_t var1;
uint32_t var2;
uint32_t var3;
// padding here
uint64_t var5;
};
è¿™æ˜¯å› ä¸ºvar1
到var3
æœ€å¤šåŠ 24个å—节,ä¸èƒ½è¢«8æ•´é™¤ã€‚ä½ çš„ç¼–è¯‘å™¨æƒ³è¦ä¸€ä¸ª8å—节整数类型在一个å¯è¢«8整除的地å€ä¸Šã€‚
在这ç§æƒ…况下,您还将在结构的末尾获得填充:
struct C
{
uint64_t memb1;
uint32_t memb2;
// Padding here
};
该填充是为memb1
数组struct C
ä¸çš„struct C c_array[13];
对é½è€Œè®¾çš„:
c_array[0].memb1
当然c_array[1].memb1
是对é½çš„ï¼Œå› ä¸ºå®ƒä½äºŽæ•°ç»„的基å€ã€‚但是 Dim bm As New Bitmap(NomeFile)
呢?如果没有结构ä¸çš„填充,它就ä¸ä¼šå¯¹é½ã€‚
C的定义方å¼æ˜¯ä¸èƒ½åœ¨æ•°ç»„å…ƒç´ ä¹‹é—´æ·»åŠ å¡«å……;æ•°ç»„çš„å…ƒç´ ç´§å¯†åˆ†é…ã€‚å› æ¤ï¼Œå¦‚果需è¦å¡«å……,则必须将其拧入元件类型ä¸ã€‚结构的布局必须考虑å¯èƒ½çš„数组èšåˆã€‚
ç”案 5 :(得分:0)
虽然我肯定有例外,但是对于结构ä¸çš„å—段以åŠæ•´ä¸ªç»“构,编译器通常会æ’入足够的填充以满足对é½è¦æ±‚。ä¸å…许C编译器对结构ä¸çš„å—段é‡æ–°æŽ’åºã€‚
ä¸åŒçš„类型å¯èƒ½å…·æœ‰ä¸åŒçš„对é½è¦æ±‚,类型的大å°å¿…须是其对é½è¦æ±‚çš„å€æ•°ã€‚在大多数64ä½ç³»ç»Ÿä¸Šï¼Œæ ‡å‡†C原è¯ç±»åž‹çš„对é½è¦æ±‚ç‰äºŽå…¶å¤§å°ã€‚通常,结构的对é½è¦æ±‚ç‰äºŽå…¶æˆå‘˜çš„最高对é½è¦æ±‚。
有时必须填充结构以确ä¿å…¶æˆå‘˜æ»¡è¶³å¯¹é½è¦æ±‚,并且结构的整体大å°æ˜¯å…¶å¯¹é½è¦æ±‚çš„å€æ•°ã€‚
å› æ¤ï¼Œè®©æˆ‘们看一下您的结构以åŠç¬¬ä¸‰ä¸ªç»“构。
struct A
{
uint32_t var1; //size 4, alignment 4, offset 0
uint32_t var2; //size 4, alignment 4, offset 4
uint32_t var3; //size 4, alignment 4, offset 8
uint32_t var4; //size 4, alignment 4, offset 12
uint32_t var5; //size 4, alignment 4, offset 16
};
所有å—段的类型å‡ä¸ºuint32_t,其大å°ä¸º4,对é½æ–¹å¼ä¸º4ã€‚å› æ¤ï¼Œæ— 需填充,该结构的总体大å°ä¸º20å—节,总体对é½æ–¹å¼ä¸º4个å—节。
struct B
{
uint32_t var1; //size 4, alignment 4, offset 0
uint32_t var2; //size 4, alignment 4, offset 4
uint32_t var3; //size 4, alignment 4, offset 8
//4 bytes of padding.
uint64_t var5; //size 8, alignment 8, offset 16
};
å‰ä¸‰ä¸ªå—段的大å°å’Œå¯¹é½æ–¹å¼ä¸º4ï¼Œå› æ¤å¯ä»¥åˆ†é…å®ƒä»¬è€Œæ— éœ€å¡«å……ã€‚ä½†æ˜¯var5的大å°å’Œå¯¹é½æ–¹å¼ä¸º8ï¼Œå› æ¤æ— 法在å移é‡12处分é…。必须æ’入填充,而var5分é…在å移é‡16处。整个结构的大å°ä¸º24,对é½æ–¹å¼ä¸º8。 >
struct C
{
uint32_t var1; //size 4, alignment 4, offset 0
uint32_t var2; //size 4, alignment 4, offset 4
uint64_t var3; //size 8, alignment 8, offset 8
uint32_t var5; //size 4, alignment 4, offset 16
//4 bytes of padding
};
在这ç§æƒ…况下,å¯ä»¥åœ¨ä¸æ’入填充的情况下将所有å˜é‡åˆ†é…ç»™åˆé€‚çš„å移é‡ã€‚但是,结构的总大å°å¿…须是其对é½è¦æ±‚çš„å€æ•°ï¼ˆå¦åˆ™æ•°ç»„å°†ç ´å对é½ï¼‰ï¼Œå› æ¤å¿…须填充结构的末端。åŒæ ·ï¼Œæ•´ä¸ªç»“构的大å°ä¸º24,对é½æ–¹å¼ä¸º8。
æŸäº›ç¼–译器具有é‡å†™ç»“æž„çš„æ£å¸¸æ‰“包的机制,例如,å¦ä¸€ä¸ªç”案ä¸æ到的__attribute__((packed))
ã€‚ä½†æ˜¯ï¼Œå¿…é¡»è°¨æ…Žä½¿ç”¨è¿™äº›åŠŸèƒ½ï¼Œå› ä¸ºå®ƒä»¬å¾ˆå®¹æ˜“å¯¼è‡´å¯¹é½å†²çªã€‚