前往
大廳
主題

C程式碼排版與記憶體對齊

Yang | 2023-03-05 13:47:37 | 巴幣 2 | 人氣 180

C關鍵字pragma pack,C#關鍵字StructLayout,網路上能找到的資料極多

最保險的寫法,資料用1個byte的寬度去對齊記憶體
C:#pragma pack(1)
C#:[StructLayout(LayoutKind.Sequential, Pack =1)]

有些系統為了效能,程式內資料會用4或8個bytes的寬度去對齊記憶體,
但把資料列印到檔案或透過網路轉送時,讀寫(收發)外部資料就要做額外處理

把資料(bytes)給客戶時,客戶讀完一個欄位後,可能要略過3或7個bytes,再讀下一個欄位,
略過的bytes,很有可能是亂碼,客戶閱讀或解析上會很不方便

因此除非有特例需要,通常我會用pragma pack(1)去對齊記憶體,
以下紀錄我寫新的class(.h/.cpp)時常用的排版

#ifndef _MY_NEW_NAMESPACE_MY_NEW_CLASS_H
#define _MY_NEW_NAMESPACE_MY_NEW_CLASS_H

#include <standard library>

#include "third party library"

using namespace OtherNamespace;
using OtherNamespace::OtherClass;

#pragma pack(1)

namespace MyNewNamespace
{
    //宣告
    class MyNewClass
    {
        public:
            //
    };

    //實作
}

#pragma pack()

#endif

把資料列印到檔案或透過網路轉送時,如果要對齊特定的資料格式,
常見的做法,會塞空白' '填充,避免亂碼

考量相容性與移植性,在程式碼上自行定義pragma pack比較好,
不同平台系統上,預設的pragma pack可能會不一樣

20230318補充,程式的進入點,main的排版,我通常會寫成

#pragma pack(1)

int main(const int argc, const char *argv[])
{
    //

    return EXIT_SUCCESS;
}

#pragma pack()

#endif

標準規範是寫成int main(int argc, char *argv[])即可,不過不會去改動的變數,我習慣在前面加上const,
原因同之前寫的,in 參數修飾詞 (C# 7.2以上支援),
避免不小心手滑改到不該改的資料,減少日後程式出錯的機率

程式結束時,沒錯return EXIT_SUCCESS,有錯return EXIT_FAILURE,也是標準的寫法

參考
Both EXIT_SUCCESS and the value zero indicate successful program execution status (see exit), although it is not required that EXIT_SUCCESS equals zero.

觀察幾個常見的平台,EXIT_SUCCESS似乎都是定義0,但標準規範沒寫一定要是0,
EXIT_SUCCESS的實際數值,應該是由各平台自行決定,
EXIT_FAILURE則可能各自有複雜的定義,只要不等於EXIT_SUCCESS即可

譬如
Windows上0代表正常關閉,1~15999微軟有定義不同的錯誤碼
送禮物贊助創作者 !
0
留言

創作回應

更多創作