再談:自定義結構體的對齊問題之__attribute__ ((packed))方法
問題來源:
我們在程式開發過程中往往會遇到這樣的問題:以某種資料格式寫入,再以此格式讀出,特別是socket通訊中,通常會遇到資料錯位問題,這就是資料結構的對齊的問題。為了讓我們的資料結構以最優的方式儲存,處理,保證讀寫資料結構都一一對齊,我們往往採用3種方式:
1.程式作者,手動對齊,將資料按從小到大的順序排列,儘量湊齊。
2.使用#pragma pack (n)來指定資料結構的對齊值。
3.使用 __attribute__ ((packed)) ,讓編譯器取消結構在編譯過程中的優化對齊,按照實際佔用位元組數進行對齊,這樣子兩邊都需要使用 __attribute__ ((packed))取消優化對齊,就不會出現對齊的錯位現象。
對於對齊的詳細概念與第2種方法的介紹請參考這裡:
位元組對齊詳解
http://blog.csdn.net/ipromiseu/archive/2009/07/12/4339537.aspx
好了,現在本篇主要是看一下 __attribute__ ((packed))的真面目,
以下部分來自網路:
1. __attribute__ ((packed)) 的作用就是告訴編譯器取消結構在編譯過程中的優化對齊,按照實際佔用位元組數進行對齊,是GCC特有的語法。這個功能是跟作業系統沒關係,跟編譯器有關,gcc編譯器不是緊湊模式的,我在windows下,用vc的編譯器也不是緊湊的,用tc的編譯器就是緊湊的。例如:
在TC下:struct my{ char ch; int a;} sizeof(int)=2;sizeof(my)=3;(緊湊模式)
在GCC下:struct my{ char ch; int a;} sizeof(int)=4;sizeof(my)=8;(非緊湊模式)
在GCC下:struct my{ char ch; int a;}__attrubte__ ((packed)) sizeof(int)=4;sizeof(my)=5
2. __attribute__關鍵字主要是用來在函式或資料宣告中設定其屬性。給函式賦給屬性的主要目的在於讓編譯器進行優化。函式宣告中的__attribute__((noreturn)),就是告訴編譯器這個函式不會返回給呼叫者,以便編譯器在優化時去掉不必要的函式返回程式碼。
GNU C的一大特色就是__attribute__機制。__attribute__可以設定函式屬性(Function
Attribute)、變數屬性(Variable Attribute)和型別屬性(Type
Attribute)。
__attribute__書寫特徵是:__attribute__前後都有兩個下劃線,並且後面會緊跟一對括弧,括弧裡面是相應的__attribute__引數。
__attribute__語法格式為:
__attribute__ ((attribute-list))
其位置約束:放於宣告的尾部“;”之前。
函式屬性(Function Attribute):函式屬性可以幫助開發者把一些特性新增到函式宣告中,從而可以使編譯器在錯誤檢查方面的功能更強大。__attribute__機制也很容易同非GNU應用程式做到相容之功效。
GNU CC需要使用 –Wall編譯器來擊活該功能,這是控制警告資訊的一個很好的方式。
packed屬性:使用該屬性可以使得變數或者結構體成員使用最小的對齊方式,即對變數是一位元組對齊,對域(field)是位對齊。
如果你看過GPSR協議在TinyOS中的實現,你一定會注意到下面的語句:
typedef struct {
double x;
double y;
} __attribute__((packed)) position_t;
開始我們還可以理解,不久是定義一個結構體嘛!不過看到後面的語句,你可能就會一頭霧水了,’ __attribute__((packed))’是什麼東西?有什麼作用?一連串的疑問馬上就會從你腦袋裡冒出來。雖然這個對理解整個程式沒有什麼影響,但我不想讓這些疑問一直呆在我的腦子裡,負擔太重。省得以後念念不忘,而且也許有一天可以用的上呢。搞清楚這個問題吧!
GNU C的一大特色(卻不被初學者所知)就是__attribute__機制。__attribute__可以設定函式屬性(Function
Attribute)、變數屬性(Variable Attribute)和型別屬性(Type
Attribute)。
__attribute__語法格式為:
__attribute__ ((attribute-list))
其位置約束為:放於宣告的尾部“;”之前。
packed是型別屬性(Type Attribute)的一個引數,使用packed可以減小物件佔用的空間。需要注意的是,attribute屬性的效力與你的聯結器也有關,如果你的聯結器最大隻支援16位元組對齊,那麼你此時定義32位元組對齊也是無濟於事的。
使用該屬性對struct或者union型別進行定義,設定其型別的每一個變數的記憶體約束。當用在enum型別定義時,暗示了應該使用最小完整的型別(it indicates that the smallest integral type should be used)。
下面的例子中,my-packed-struct型別的變數陣列中的值會緊湊在一起,但內部的成員變數s不會被“pack”,如果希望內部的成員變數也被packed的話,my-unpacked-struct也需要使用packed進行相應的約束。
struct my_unpacked_struct
{
char c;
int i;
};
struct my_packed_struct
{
char c;
int i;
struct my_unpacked_struct s;
}__attribute__ ((__packed__));
__attribute__機制的詳細介紹請參考:
相關推薦
再談:自定義結構體的對齊問題之__attribute__ ((packed))方法
問題來源: 我們在程式開發過程中往往會遇到這樣的問題:以某種資料格式寫入,再以此格式讀出,特別是socket通訊中,通常會遇到資料錯位問題,這就是資料結構的對齊的問題。為了讓我們的資料結構以
自定義結構體的對齊問題
一、跨平臺通用資料型別 之前的一篇部落格Linux資料型別(通用移植),已經自定義嘗試解決了資料通用型別問題。 這裡通過原始碼進行分析,利用原始碼進行解決問題。在<stdint.h>中我們發現: typedef signed char int8_t; typedef
Solidity學習::(10)自定義結構體
自定義結構體 定義 跟其他語言類似 //學生 struct Student{ string name; int num; } //班級 struct Class{ string clsName; //學生的列表
QT:用QSet儲存自定義結構體的問題
前幾天要用QSet作為儲存一個自定義的結構體(就像下面這個程式一樣),結果死活不成功。。。後來還跑到論壇上問人了,丟臉丟大了。。。 事先說明:以下這個例子是錯誤的 [cpp] view plaincopyprint? #include <QtCore> struct node
自定義結構體做為map裡面的key的寫法
其中一種寫法: struct hook_info { string lib_name; string fun_name; int param_count; bool bIATHook; hook_info(char *lib
自定義結構體及初始化
自定義結構體及初始化,以及標頭檔案先宣告巨集,然後宣告結構體 <pre name="code" class="cpp">/********************** macro definition **********************/ #ifndef CVALGO_
C++ 自定義結構體的Priority Queue
比較函式return true 意味著排序需要交換。 #include <iostream> #include <queue> #include <vector> #include <algorithm> using namespace
利用qt 訊號槽傳遞自定義結構體--藉助QVariant
在前面的部落格裡,我介紹了利用Q_DECLARE_METATYPE和qRegsterMetaType來傳遞自定義的結構體。但是這樣做有個缺點:qRegisterMetaType()只能在main()函式裡才能發揮作用。https://blog.csdn.net/Kelvin_Yan/article/
QT訊號槽傳遞自定義結構體
QT的訊號槽可以傳遞int, short, double等c語言的常用型別的變數,也可以傳遞如QImage之類的QT支援 的型別。但是如何傳遞一個程式設計師自定義的結構體? 1)在定義結構體之後,要呼叫Q_DECLARE_METATYPE,向QT宣告這個結構體 2)在main.cpp 中,用
[UE4]自定義結構體、類、資料表
自定義資料表: #pragma once #include "CoreMinimal.h" #include "Engine/UserDefinedStruct.h" #include "Components/CanvasPanel.h" #include "Blueprint/UserW
[UE4]自定義結構體、類、數據表
png table 小地圖 比例 pub 地圖 sse 面板 gpa 自定義數據表: #pragma once #include "CoreMinimal.h" #include "Engine/UserDefinedStruct.h" #include "
Linux核心dev_set_drvdata()和dev_get_drvdata()儲存自定義結構體用法
定義位置:kernel/msm-3.18/include/linux/device.h static inline void dev_set_drvdata(struct device *dev, void *data){ dev->driver_data = data; } stat
Solidity的自定義結構體深入詳解
一.結構體定義 結構體,Solidity中的自定義型別。我們可以使用Solidity的關鍵字struct來進行自定義。結構體內可以包含字串,整型等基本資料型別,以及陣列,對映,結構體等複雜型別。陣列,對映,結構體也支援自定義的結構體。我們來看一個自定義結構體的定義: pragma solidit
C/C++動態自定義結構體陣列例項鍛鍊-學生成績排序
/************************************************************************/ /* 本程式是對動態記憶體、動態陣列、結構體、函式的綜合應用。 */ /***********************
35.再談SpringBoot自定義日誌配置--LogBack.xml
在實際專案開發中我們可能自定義日誌配置檔案。 以下為自定義LogBack配置。 application.properties logging.config=classpath:logback-spring.xml logback-spring.xml 以下配置日誌具有日
iOS 自定義結構體、結構體轉換成物件
1、新建一個頭檔案,如下程式碼: #ifndef Header_h #define Header_h struct MyStruce{ char *name;//(指標形式) char *address; CGFloat age;
map的鍵使用自定義結構體
背景: map的定義 template<class Key, class T, class Pred = less<Key>, class A = allocator<T> > 可見,map的定義是一個模板類,模板引數為Key,
關於Go語言,自定義結構體標籤的一個妙用.
在Go中首字母大小寫,決定著這此變數是否能被外部呼叫, 例如:在使用標準庫的json編碼自定一的結構的時候: <pre style="margin-top: 0px; margin-bottom: 0px;"><span style=" font-weig
使用STL去除std::vector自定義結構體重複項
最近搞了一個小東西要去除一個vector中重複的項。是這樣的:我用組播搜尋裝置,得到裝置IP資訊、版本號資訊,等,但有時會接收到多個相同IP裝置的資訊,因此要過濾掉重複的IP。我使用vector儲存每臺裝置資訊,包括IP、版本號,因此需要使用結構體。另外,要對這些裝置IP進
自定義結構體排序
#include <cstdio> #include <iostream> #include <iterator> #include <cstring>