1. 程式人生 > >關於C語言位元組對齊之結構體 共用體佔用位元組數的快速計算方法總結

關於C語言位元組對齊之結構體 共用體佔用位元組數的快速計算方法總結

前幾天在做專案時,出現了一個套接字通訊的一個問題,看似客戶端和伺服器端使用的一個相同的結構體,但是就是在伺服器端不能把客戶端傳送的資料全部顯示的打印出來。查找了好久的錯誤,才發現原來兩端的結構體看似相同,但其兩端結構體佔用的位元組數是不一樣的。才導致了伺服器端不能正常的顯示出全部內容。

大概情況是這樣的,client端定義結構體如下:

typedef  struct _u64{
    long high;
    long low;

}U64;
struct _data_pack{
    int a;
    int b;
    union snmp_data{
   
       long     name;
       U64  	buf1;
       char 	buf2[100];
   }snmp_data_t;

}data_pack_t;
client這端傳送sizeof(data_pack_t)的位元組到服務端。

服務端定義如下:

typedef unsigned long long U64;
struct _data_pack{
    int a;
    int b;
    union snmp_data{
   
       long 	name;
       U64  	buf1;
       char 	buf2[100];
    }snmp_data_t;

}data_pack_t;

struct data5{

		char c1;
		char c2[2];
};

服務端也接受sizeof(data_pack_t)這麼多的位元組數。

問題出現了,服務端這邊不能不能把共用體中的資料顯示的打印出來,查詢原因,最後才發現原來兩邊的結構體大小佔用的位元組數是不一樣的。

client端:sizeof(data_pack_t)= 108

service端:sizeof(data_pack_t)= 112

為此,本人在網上查找了大量有關位元組對齊的資料,總結了自己認為快速計算結構體 共用體位元組大小的方法,現說明如下:

對於無論是 簡單型別的變數 還是結構型別的變數 ,聯合型別的變數,在記憶體中的儲存都要按照位元組對齊的方式儲存。這樣儲存的主要的目的是能讓cpu快速的訪問資料。

說到位元組對齊,這裡有幾個重要的概念需要深刻理解 ,記憶:

一 :什麼是位元組對齊

     就是變數儲存的地址是變數的有效位元組對齊值的整數倍,即:

     address%最終有效位元組對齊值 = 0;

二:關於幾種位元組對齊值的說明

1 變數的自身位元組對齊值

1.1 簡單型別變數 :

    對於char型資料,其自身對齊值為1,對於short型為2,對於int,float,double型別,其自身對齊值為4,單位位元組。

1.2結構型別或聯合型別:

   自身位元組對齊值的大小是其成員中最大基本型別要求的有效位元組對齊值

2 編譯器要求的位元組對齊值:

  編譯器設定要求的位元組對齊值

3 最終有效的位元組對齊值:

  在自身位元組對齊值和編譯器要求的位元組對齊值中取較小的。

在我的編譯器環境下,預設要求4位元組對齊,把上述方法最終列成表項,可以更加直觀的表示,如下表所示:

char

short

int

double

float

自身對齊值

1

2

4

8

4

編譯器要求對齊值

4

4

4

4

4

有效對齊值

1

2

4

4

4

以上表項的規則適合簡單型別變數,也適合結構型別,聯合型別。

4  對於結構型別,聯合型別計算佔用位元組大小時遵循下面規則:

4.1結構型別:

   首先要求結構內所有變數位元組對齊 最後還要保證整個結構型別對齊(可以參考規則1.2)。

4.2聯合型別:

   首先要求聯合內佔最大位元組數的變數位元組對齊 ,最後還要保證整個聯合型別對齊(參考規則1.2)。

三 舉例說明:

例1:

struct data1{

              charc1;

              charc2[2];

};

sizeof(struct data1) = 3;

說明:假設data1從0x0000地址開始存放,該例子沒有指定位元組對齊,在GCC預設狀態下為4位元組對齊,第一個變數c1,自身位元組對齊值為1 ,比編譯器要求的位元組對齊值小,所以有效對齊值為1 ,存放地址符合0x0000%1 = 0。 第二個成員為一個數組,要求陣列對齊,則陣列內每個成員都對齊,成員為char型別,和c1相同。所以c2的存放地址 0x0001%1 = 0, 最後要求data1對齊。

例2:

struct B
{
 char b;
 int a;
 short c;
};
假設B從地址空間0x0000開始排放。該例子中沒有定義指定對齊值,在筆者環境下,該值預設為4。第一個成員變數b的自身對齊值是1,比指定或者預設指定對齊值4小,所以其有效對齊值為1,所以其存放地址0x0000符合0x0000%1=0.第二個成員變數a,其自身對齊值為4,所以有效對齊值也為4,所以只能存放在起始地址為0x0004到0x0007這四個連續的位元組空間中,複核0x0004%4=0,且緊靠第一個變數。第三個變數c,自身對齊值為2,所以有效對齊值也是2,可以存放在0x0008到0x0009這兩個位元組空間中,符合0x0008%2=0。所以從0x0000到0x0009存放的都是B內容。再看資料結構B的自身對齊值為其變數中最大對齊值(這裡是b)所以就是4,所以結構體的有效對齊值也是4。根據結構體圓整的要求,0x0009到0x0000=10位元組,(10+2)%4=0。所以0x0000A到0x000B也為結構體B所佔用。故B從0x0000到0x000B共有12個位元組,sizeof(struct B)=12;其實如果就這一個就來說它已將滿足位元組對齊了,因為它的起始地址是0,因此肯定是對齊的,之所以在後面補充2個位元組,是因為編譯器為了實現結構陣列的存取效率,試想如果我們定義了一個結構B的陣列,那麼第一個結構起始地址是0沒有問題,但是第二個結構呢?按照陣列的定義,陣列中所有元素都是緊挨著的,如果我們不把結構的大小補充為4的整數倍,那麼下一個結構的起始地址將是0x0000A,這顯然不能滿足結構的地址對齊了,因此我們要把結構補充成有效對齊大小的整數倍.其實諸如:對於char型資料,其自身對齊值為1,對於short型為2,對於int,float,double型別,其自身對齊值為4,這些已有型別的自身對齊值也是基於陣列考慮的,只是因為這些型別的長度已知了,所以他們的自身對齊值也就已知了

有了上述方法,再來計算client端結構體大小;

sizeof(union snmp_data) = 100

服務端:

sizeof(union snmp_data) =104

參考引用資料:

歡迎討論 指出錯誤 共同進步。




相關推薦

關於C語言位元組結構 共用佔用位元組快速計算方法總結

前幾天在做專案時,出現了一個套接字通訊的一個問題,看似客戶端和伺服器端使用的一個相同的結構體,但是就是在伺服器端不能把客戶端傳送的資料全部顯示的打印出來。查找了好久的錯誤,才發現原來兩端的結構體看似相同,但其兩端結構體佔用的位元組數是不一樣的。才導致了伺服器端不能正常的顯示

關於C語言記憶體,提高定址效率問題

前言: 計算機的記憶體都是以位元組為單位來劃分的,CPU一般都是通過地址匯流排來訪問記憶體的,一次能處理幾個位元組,就命令地址匯流排去訪問幾個位元組,32位的CPU一次能處理4個位元組,就命令地址匯流排一次讀取4個位元組,讀少了浪費主頻,讀多了也處理不了。64位的CPU一般

c語言記憶體與#pragma pack(n)

一、什麼是記憶體對齊,為什麼要記憶體對齊  現在計算機記憶體空間都是按照byte位元組劃分的,理論上講對任何型別的變數的訪問可以從任何地址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體地址上訪問,這就需要各種資料型別按照一定的規則在空間上排列,而不是一個接一個

C語言 結構位元組問題

摘選自這位大神的部落格 方法一: 結構體在記憶體中分配一塊連續的記憶體,但結構體內的變數並不一定是連續存放的,這涉及到記憶體對齊。原則1  資料成員對齊規則:結構(struct或聯合union)的資料成員,第一個資料成員放在offset為0的地方,以後每個資料成員儲存的起始位置要從該成員大小的整

C語言struct大小、首地址與記憶體—由結構成員地址得到結構首地址

被問到如下問題:給定一個結構體中某個變數地址,可否得到結構體變數的地址? 答案是可以,但是對不同的場合有不同的結果;這與微處理器平臺、編譯器的處理不可分割。 首先,對於處理器,大尾端、小尾端的因素必須考慮; 其次: 一、 ANSIC標準中並沒有規定,相鄰宣告的變數在記憶體中一定要相鄰。 為了程式的高效性,

C語言結構位元組例項【C語言筆試題】

 一、筆試題目:在一個64位的作業系統中定義如下結構體: <span style="font-family:Microsoft YaHei;font-size:12px;">struct st_task { uint16_t id; uint32

C語言結構位元組原則

為什麼要對齊?     現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何地址開始,但實際情況是在訪問特定型別變數的時候經常在特 定的記憶體地址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的一個接一個的排放,

什麼是C語言結構位元組,為什麼要?

一、概念     對齊跟資料在記憶體中的位置有關。如果一個變數的記憶體地址正好位於它長度的整數倍,他就被稱做自然對齊。比如在32位cpu下,假設一個整型變數的地址為0x00000004,那它就是自然對齊的。       二、為什麼要位元組對齊        需要位元

C語言查缺補漏(七)結構記憶體原則

忽略點七:結構體記憶體對齊原則 ​ 直到前幾個星期做了一道選擇題才知道,結構體元素的宣告順序可能影響結構體使用時所需的記憶體大小!!! ​ 一查才知道,在C語言中結構體有記憶體對齊原則,這個原則可以總結為兩點: ——資料成員對齊規則: ​ 結構體或聯合體的資料

C 構造型別 陣列、列舉、聯合體、結構(位段) 位元組 和 大小端儲存

列舉 .列舉:被命名的標籤常量(對事物的列出) ---型別的構造------- enum key{    UP,                             //成員<標籤常量:預設第一個為0 後一個總是前一個的值加一>    DOWN,    L

C/C++ 結構位元組詳解

結構體的sizeof 先看一個結構體: struct S1 { char c; int i; }; 12345 structS1{charc;in

C/C++結構位元組詳解

前提:為了訪問速度和效率,需要各種型別資料按照一定的規則在空間上排列; 不是所有的硬體平臺都能訪問任意地址上的任意資料的;某些硬體平臺只能在某些地址處取 某些特定型別的資料,否則丟擲硬體異常。 為了訪問未對⻬的記憶體,處理器需要作兩次記憶體訪問;⽽對⻬的記憶體訪問僅需要

C語言記憶體位元組

1.結構體的記憶體大小 比如下面這段程式碼: #include<stdio.h> #include<stdlib.h> struct arr { int a; int b; }; int main() {

C++中結構位元組問題

  前不久,在C++程式中碰到一個有關結構體位元組對齊的問題。 一。問題描述 在程式中,定義了一個結構體,如下:typedef struct{   char name[33];   int ID;   int  age;} PERSON; 聲明瞭一個該結構體的陣列:PERSO

C語言位元組問題(以32位系統為例)

  1. 什麼是對齊?   現代計算機中記憶體空間都是按照位元組(byte)劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何地址開始,但實際情況是在訪問特定變數的時候經常在特定的記憶體地址訪問,這就需要各型別資料按照一定的規則在空間上排列,而不是順序地一個接一個地排放,這就是對齊

C語言結構 共用 列舉 typedef

結構體型別和結構體變數, struct 定義結構體型別時 不佔記憶體 匿名結構體,無法建立變數訪問,有限的結構體型別變數 結構體變數不能整體引用,只能引用變數成員 結構體變數用大括號賦值,只有在建立並初始化的時候才可以 #define _CRT_SECURE_NO_WARN

詳解結構、類等記憶體位元組

先說個題外話:早些年我學C程式設計時,寫過一段解釋硬碟MBR分割槽表的程式碼,對著磁碟編輯器怎麼看,怎麼對,可一執行,結果就錯了。當時除錯也不太會,又根本沒聽過結構體對齊這一說,所以,問題解決不了,好幾天都十分糾結。後來萬般無奈請教一個朋友,才獲悉可能是結構體對齊的事,一查、一改,果真如此。 &

結構位元組

在用sizeof運算子求算某結構體所佔空間時,並不是簡單地將結構體中所有元素各自佔的空間相加,這裡涉及到記憶體位元組對齊的問題。 1) 結構體變數的首地址能夠被其最寬基本型別成員的大小所整除; 2) 結構體每個成員相對結構體首地址的偏移量都是成員大小的整數倍; 3) 結構體的總大小為結構

C語言位元組問題詳解

部落格園 首頁 新隨筆 聯絡 管理 訂閱 隨筆- 80  文章- 0  評論- 125  引言      考慮下面的結構體定義: 1 typedef struct{ 2 char c1; 3 short s; 4

C語言位元組及設定編譯方式方法

  一、概念         對齊跟資料在記憶體中的位置有關。如果一個變數的記憶體地址正好位於它長度的整數倍,他就被稱做自然對齊。比如在32位cpu下,假設一個整型變數的地址為0x00000004,那它就是自然對齊的。       二、為什麼要位元組對齊        需要位