【C語言】結構體內存對齊:熱門面試話題

請添加圖片描述
🔥引言

書接上文,我們了解關于結構體的基本知識,這篇將深入剖析結構體中一個重要的知識點:內存對齊
關于內存對齊是屬于熱門面試話題,對此單獨放在一篇來分享

請添加圖片描述

Alt

🌈個人主頁:是店小二呀
🌈C語言筆記專欄:C語言筆記
🌈C++筆記專欄: C++筆記

🌈喜歡的詩句:無人扶我青云志 我自踏雪至山巔
請添加圖片描述

文章目錄

  • 一、結構體中內存對齊
    • 1.1 對齊規則
    • 1.2 內存對齊的意義
    • 1.3 #pragma(預處理指令)
      • 1.3.1 pragma相關介紹
      • 1.3.2 #pragma pack(n)修改默認對齊數
  • 二、結構體實現位段
    • 2.1 位段的概念
    • 2.2 位段的內存分配
    • 2.3 位段的跨平臺問題
    • 2.4 位段的應用


一、結構體中內存對齊

1.1 對齊規則

  • 結構體第一個成員變量對齊相對于結構體成員地址偏移量為0的位置上

  • 其他成員變量需要對齊到對齊數的整數倍

  • 結構體總大小最大對齊數的正數倍

如果存在嵌套結構體的情況,嵌套結構體占用空間需要對齊自身最大對齊數的整數倍,同時在計算結構體總大小的時候,嵌套結構體的最大對齊數參與比較

注意】:對齊數 == 編譯器默認的一個對齊數與該成員變量大小的較小值

  • 在vs環境下,系統默認對齊為8

  • 在Linux中沒有默認對齊數,對齊數就是成員自身的大小


通過題目熟練的掌握以上知識.

struct S1
{char c1;int i;char c2;
};
printf("%d\n", sizeof(struct S1));--12struct S2
{char c1;char c2;int i;
};
printf("%d\n", sizeof(struct S2));--8struct S4
{char c1;struct S2 s2;double d;
};
printf("%d\n", sizeof(struct S2));--24

在這里插入圖片描述
在這里插入圖片描述

說明】:數值代表的是結構體變量地址處的偏移量


1.2 內存對齊的意義

?部分的參考資料都是這樣說的

平臺原因(移植原因)

  • 不是所有的硬件平臺都能訪問任意地址上的任意數據的;某些硬件平臺只能在某些地址處取某些特定類型的數據,否則拋出硬件異常

性能原因

  • 數據結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在于,為了訪問未對齊的內存,處理器需要作兩次內存訪問;對齊的內存訪問僅需要?次訪問。

假設?個處理器總是從內存中取8個字節,則地址必須是8的倍數。如果我們能保證將所有的double類型的數據的地址都對齊成8的倍數,那么就可以用一個內存操作來讀或者寫值了。否則,我們可能需要執行兩次內存訪問,因為對象可能被分放在兩個8字節內存塊中。

總體來說:結構體的內存對齊是拿空間來換取時間的做法

!(https://img-blog.csdnimg.cn/direct/db9b7a7f327947f7a81d64a1a2254b68.gif)

通過上述的觀察,不難看出。如果不存在內存對齊,需要執行兩個內存訪問(對象被分放在兩塊內存塊),而內存對齊只需要進行一次。

對此在涉及結構體時,需要考慮滿足對齊,又要節省空間。可以將占用空間小的成員盡量集中在一起

struct S1
{char c1;int i;char c2;
};
struct S2
{char c1;char c2;int i
};
S2 < S1

1.3 #pragma(預處理指令)

1.3.1 pragma相關介紹

  • 用于指定計算機或操作系統特定的編譯器功能
  • 根據定義pragma指令是計算機或操作系統特定的,并且通常對于每個編譯器而言都有所不同
  • pragma指令可用于條件語句以提供新的預處理器功能,或為編譯器提供實現所定義的信息,

1.3.2 #pragma pack(n)修改默認對齊數

#include <stdio.h>
#pragma pack(1)//設置默認對齊數為1
struct S
{char c1;int i;char c2;
};
#pragma pacK()//取消默認對齊數,還原為默認對齊數
int main()
{printf("%d\n",sizeof(struct S));return 0;
}

推薦使用場景,在結構體進行內存對齊時,如果對于對齊方式不能達到預期,可以通過該指令更改默認對齊數

獲得該成員變量的偏移量

這里需要使用一個函數offsetof()宏,該函數被聲明在stddef.h文件中,以下是函數offsetof()宏

size_t offsetof(type,member);

宏定義】:

#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE*)0)->MEMBER)

如果想要了解更多,可以參考下這篇博客Offsetof宏詳解-CSDN博客.這里只如何去使用Offsetof()宏計算出結構體某成員地址的偏移量。

#include <stdio.h>
#include <stddef.h>
struct S
{char a;int i;
};
int main()
{printf("%d\n",offsetof(struct S,i));//那么這里的結果就是就是4return 0;
}

小總結】:
結構體中的內存對齊是為了以空間換取時間的做法,隨著計算機不斷地更新換代,一般不需要擔心內存空間不足的問題,逐漸地從更多考慮的是時間上的問題。同時為了節約空間的開銷,提出位段


二、結構體實現位段

2.1 位段的概念

位段是結構體的一種變形,在功能、用法上與結構體基本一致,但是在于內存分配上不同,位段可以很好的節省空間,可存在位段跨平臺的問題。同時與結構體相比有兩個點不同。

  • 成員上:intunsigned intsigned int,但是在C99中是可以選擇其他類型
  • 格式上:位段成員名后面有一個冒號和一個數字
struct A
{char _a:2;char _b:5;
};

【說明】:這里數字代表的是該成員變量占用空間大小,而大小單位是比特

【問題】:位段A所占的內存大小是多大?

這個問題,需要利用下面的知識了


2.2 位段的內存分配

  • 位段成員:intunsigned intsigned int或者char等類型(需要是整形,是要轉換為二進制
  • 位段開辟空間的大小一般是以四個字節或一個字節開辟的
  • 位段涉及許多不確定的因素,位段是不跨平臺的,注意可移植的程序,應該避免使用位段
struct S
{char a:3;char b:4;char c:5;char d:4;
};struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

2.3 位段的跨平臺問題

不確定的因素大致包括】:

  1. 內存存放的方向是從左到右,還是從右到左
  2. 是低地址到高地址,還是高地址到低地址
  3. int類型是不確定是被當作有符號數還是無符號數
  4. 當一個結構體包括了兩個位段,第二個位段比較大,無法容納第一個位段剩下的空間,是舍棄還是利用剩下的空間,這是不確定的
  5. 位段中最大位的數目不能確定(16位機器最大16,32位機器最?32,寫成27,在16位機器會出問題),可能會沖出最大的范圍,出現問題

我們不妨以vs2013環境下測量下數據

vs2013下,位段是從左到右,從低地址到高地址,位段需要的空間不足,直接開辟一塊新的空間,我們來結合圖片理解下

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

【步驟】:

  1. 位段開辟八個bit位(這里是char類型的情況)
  2. 位段成員后面數字是占用多少bit位
  3. 根據變量數據,轉化為二級制(一個二級制為一個比特位),根據位段對應的數據,將轉為的二級制多個比特位放入
  4. 關于上不確定因素中(4),vs2013選擇舍棄,那就開辟一塊新的空間,重復(1,2,3)步驟

2.4 位段的應用

比如下圖中網絡協議中,在一個結構存在很多只需要幾個bit位就能實現的效果,這里使用位段就能達到想要的效果,也能節省空間的浪費。同時網絡傳輸的數據大小也會小一點,提高了網絡的流暢和效率!

位段使用注意事項】:

struct A
{int _a:2;int _b:5;
};
int main()
{//錯誤的做法struct A s={0};scanf("%d",&s._a);//正確的示范int b=0;scanf("%d",&b);s._b=b;return 0;
}

說明】:

位段的幾個成員共有同一個字節,而有些成員的起始位置并不是某個字節的起始位置。對此這些位置是沒有地址(內存中每個字節分配一個地址,一個字節內部的bit位是沒有地址的

解決辦法】:

可以將值放入一個變量中,再通過賦值給位段成員,這個賦值在以后的操作中,是很巧妙的用法的。


在這里插入圖片描述
以上就是本篇文章的所有內容,在此感謝大家的觀看!這里是店小二C語言筆記,希望對你在學習C語言中有所幫助!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/14007.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/14007.shtml
英文地址,請注明出處:http://en.pswp.cn/web/14007.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

3D工業視覺

前言 本文主要介紹3D視覺技術、工業領域的應用、市場格局等&#xff0c;主要技術包括激光三角測量、結構光、ToF、立體視覺。 一、核心內容 3D視覺技術滿足工業領域更高精度、更高速度、更柔性化的需求&#xff0c;擴大工業自動化的場景。 2D視覺技術基于物體平面輪廓&#…

軟件無線電學習-第二代移動通信系統過程理解

本文知識內容摘自《軟件無線電原理和應用》 無線通信領域讓大家感受最深的是民用移動通信的快速發展。民用移動通信在短短的二十年時間里已發展了三代&#xff1a;20世紀80年代的模擬體制(TACS/AMPS)為第一代移動通信(簡稱1G)&#xff1b;20世紀90年代的數字體制(GSMCDMATDMA)…

Git提交和配置命令

一、提交代碼到倉庫 在軟件開發中&#xff0c;版本控制是一個至關重要的環節。而Git作為目前最流行的版本控制系統之一&#xff0c;為我們提供了便捷高效的代碼管理和協作工具。在日常開發中&#xff0c;我們經常需要將本地代碼提交到遠程倉庫&#xff0c;以便于團隊協作和版本…

2024電工杯數學建模B題思路模型代碼

完整內容更新見文末名片 B 題&#xff1a;大學生平衡膳食食譜的優化設計及評價 大學時代是學知識長身體的重要階段&#xff0c;同時也是良好飲食習慣形成的重要時期。這一特 定年齡段的年輕人&#xff0c;不僅身體發育需要有充足的能量和各種營養素&#xff0c;而且繁重的腦…

Java基礎教程 - 9 集合

更好的閱讀體驗&#xff1a;點這里 &#xff08; www.doubibiji.com &#xff09; 更好的閱讀體驗&#xff1a;點這里 &#xff08; www.doubibiji.com &#xff09; 更好的閱讀體驗&#xff1a;點這里 &#xff08; www.doubibiji.com &#xff09; 9 集合 什么是集合&…

【stm32/CubeMX、HAL庫】嵌入式實驗六:定時器(2)|PWM輸出

參考&#xff1a; 【【正點原子】手把手教你學STM32CubeIDE開發】 https://www.bilibili.com/video/BV1Wp42127Cx/?p13&share_sourcecopy_web&vd_source9332b8fc5ea8d349a54c3989f6189fd3 《嵌入式系統基礎與實踐》劉黎明等編著&#xff0c;第九章定時器&#xff0c…

愛普生TG5032SFN溫補晶振在機器人控制中的應用

機器人控制是機器人技術的核心組成部分&#xff0c;它涉及通過傳感器采集外部環境信息&#xff0c;然后經過信號處理、運動規劃和執行控制等步驟&#xff0c;最終實現機器人的運動控制和任務執行。在技術的不斷更選&#xff0c;機器人控制也在不斷進步和演變。智能化機器人具備…

cannot compute sizeof(off_t) when compile netcdf-fortran

export LD_LIBRARY_PATH/netcdf-c/lib:$LD_LIBRARY_PATH

Z緩沖技術在AI去衣中的關鍵角色

引言&#xff1a; 人工智能&#xff08;AI&#xff09;技術的飛速發展&#xff0c;為圖像處理領域帶來了革命性的變化。其中&#xff0c;AI去衣技術作為一種新興的應用&#xff0c;引起了廣泛關注。它不僅在多媒體內容的編輯、虛擬現實和增強現實等領域具有重要的應用價值&…

Jenkins 構建 Maven 項目:項目和服務器在一起的情況

bash.sh內容 #!/bin/bash#刪除歷史數據 rm -rf ruoyi-admin.jar# appname$1 appnamevideo.xxxxx.com #獲取傳入的參數 echo "arg:$appname"#獲取正在運行的jar包pid # pidps -ef | grep $1 | grep java -jar | awk {printf $2} pidps -ef | grep $appname | grep ja…

1673. 找出最具競爭力的子序列

題目 給定一個整數數組 nums 和一個正整數 k&#xff0c;返回長度為 k 且最具競爭力的 nums 子序列。 數組的子序列是從數組中刪除一些元素&#xff08;可能不刪除元素&#xff09;得到的序列。 在子序列 a 和子序列 b 第一個不相同的位置上&#xff0c;如果 a 中的數字小于…

mysql 刪除特殊字符 表中存了特殊字符 換行符 回車符 word字符 查詢不到

省流&#xff1a; UPDATE t1 SET f1 REPLACE(REPLACE( f1 , CHAR(10), ), CHAR(13), ); 用 replace() 函數將 換行符char(10) 和 回車符char(13) 替換為空字符串。 char(10)&#xff1a;換行 char(13)&#xff1a;回車 發現表里存進很多換行符&#xff0c;如下圖&#xff1a…

深入研究Qt Meta - Object System

目錄 先說RTTI 再說QMeta Object System 關于Q_OBJECT 這篇文章我打算研究一下QMetaObject System&#xff0c;也就是Qt自己構建起來的元對象系統。 先說RTTI 啥是RTTI&#xff1f;這是C編程里的一個常見術語&#xff0c;全稱是&#xff1a;運行階段類型識別&#xff08;Ru…

Chrome DevTools攻略

Chrome DevTools&#xff0c;也稱為Chrome開發者工具&#xff0c;是一套直接內置于Google Chrome瀏覽器的Web開發者工具。以下是一些使用Chrome DevTools的攻略和技巧&#xff1a; 打開DevTools&#xff1a; 右鍵點擊頁面上的任何元素&#xff0c;選擇“檢查”或“審查元素”。…

2024年華為OD機試真題-機場航班調度程序-C++-OD統一考試(C卷D卷)

題目描述: XX市機場停放了多架飛機,每架飛機都有自己的航班號CA3385,CZ6678,SC6508等,航班號的前2個大寫字母(或數字)代表航空公司的縮寫,后面4個數字代表航班信息。但是XX市機場只有一條起飛用跑道,調度人員需要安排目前停留在機場的航班有序起飛。為保障航班的有序起…

【webrtc】MediaEngine的實現CompositeMediaEngine創建VOE

m98音視頻的引擎是管理channel的看起來是外部強加給CompositeMediaEngine 管理的。CompositeMediaEngine :合成媒體引擎 G:\CDN\rtcCli\m98\src\media\base\media_engine.h// CompositeMediaEngine constructs a MediaEngine from separate // voice and video engine classes…

Python中文分詞工具庫之jieba使用詳解

概要 在自然語言處理(NLP)領域,中文文本的分詞是一個重要且基礎的任務。Python的jieba庫是一個廣泛使用的中文分詞工具,提供了豐富的功能,包括精準模式、全模式、搜索引擎模式等,適用于不同的應用場景。本文將詳細介紹jieba庫,包括其安裝方法、主要特性、基本和高級功能…

代碼隨想錄35期Day49-Java

Day49題目 LeetCode123買賣股票三 核心思想:和昨天的買賣股票相比,這個只允許買兩次,因此把狀態新增幾個,可見代碼注釋 class Solution {public int maxProfit(int[] prices) {// 設置五個狀態 0 : 無操作 , 1 : 第一次買入, 2 : 第一次賣出 , 3: 第二次買入, 4:第二次賣出…

java技術:oauth2協議

目錄 一、黑馬程序員Java進階教程快速入門Spring Security OAuth2.0認證授權詳解 1、oauth服務 WebSecurityConfig TokenConfig AuthorizationServer 改寫密碼校驗邏輯實現類 2、oauth2支持的四種方式&#xff1a; 3、oauth2授權 ResouceServerConfig TokenConfig 4、…

前端面試題日常練-day19 【面試題】

題目 希望這些選擇題能夠幫助您進行前端面試的準備&#xff0c;答案在文末。 1. AJAX是什么的縮寫&#xff1f; A. Asynchronous JavaScript and XMLB. Asynchronous JavaScript and XHTMLC. Asynchronous Java and XMLD. Asynchronous Java and XHTML2. 下列哪個方法用于創建…