C/C++ sizeof 用法與範例

本篇 ShengYu 介紹 C/C++ sizeof 用法與範例,sizeof 是用來計算資料類型在該平台記憶體中所佔用 bytes 數。

以下 C/C++ sizeof 的用法介紹將分為這幾部份,

  • sizeof 基本類型
  • sizeof 自定義類型 struct / class
  • sizeof 資料結構對齊問題

那我們開始吧!

sizeof 基本類型

sizeof 回傳的是 size_t,要 print size_t 的話要用 %zu,才不會遇到型別不對的編譯警告,

cpp-sizeof.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// g++ cpp-sizeof.cpp -o a.out
#include <stdio.h>

int main() {
printf("sizeof(char) %zu\n", sizeof(char));
printf("sizeof(unsigned char) %zu\n", sizeof(unsigned char));
printf("sizeof(short) %zu\n", sizeof(short));
printf("sizeof(unsigned) %zu\n", sizeof(unsigned));
printf("sizeof(int) %zu\n", sizeof(int));
printf("sizeof(unsigned int) %zu\n", sizeof(unsigned int));
printf("sizeof(long) %zu\n", sizeof(long));
printf("sizeof(float) %zu\n", sizeof(float));
printf("sizeof(double) %zu\n", sizeof(double));

return 0;
}

我的平台輸出如下,基本上資料類型有無 unsigned 都是同一個大小,char 的大小是 1 byte,int 的大小是 4 bytes,

1
2
3
4
5
6
7
8
9
sizeof(char)           1
sizeof(unsigned char) 1
sizeof(short) 2
sizeof(unsigned) 4
sizeof(int) 4
sizeof(unsigned int) 4
sizeof(long) 8
sizeof(float) 4
sizeof(double) 8

如果是用 sizeof(變數) 的話,就會計算該變數的資料類型的大小,範例如下,

cpp-sizeof2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// g++ cpp-sizeof2.cpp -o a.out
#include <iostream>
using namespace std;

int main() {
char c = 'a';
short s = 123;
int i = 456;
long l = 789;
float f = 3.5;
double d = 3.14;
cout << "sizeof(char) " << sizeof(c) << '\n';
cout << "sizeof(short) " << sizeof(s) << '\n';
cout << "sizeof(int) " << sizeof(i) << '\n';
cout << "sizeof(long) " << sizeof(l) << '\n';
cout << "sizeof(float) " << sizeof(f) << '\n';
cout << "sizeof(double) " << sizeof(d) << '\n';

return 0;
}

我的平台輸出如下,

1
2
3
4
5
6
sizeof(char)          1
sizeof(short) 2
sizeof(int) 4
sizeof(long) 8
sizeof(float) 4
sizeof(double) 8

如果是用 sizeof 陣列的話,範例如下,

cpp-sizeof3.cpp
1
2
3
4
5
6
7
8
9
10
11
12
// g++ cpp-sizeof3.cpp -o a.out
#include <iostream>
using namespace std;

int main() {
int num[10];
cout << "sizeof(int[10]) " << sizeof(int[10]) << '\n';
cout << "sizeof num " << sizeof(num) << '\n';
cout << "length of num " << sizeof(num) / sizeof(num[0]) << '\n';

return 0;
}

我的平台輸出如下,

1
2
3
sizeof(int[10])  40
sizeof num 40
length of num 10

sizeof 自定義類型 struct / class

sizeof 自定義類型 struct 或 class 的範例如下,

cpp-sizeof4.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// g++ cpp-sizeof4.cpp -o a.out
#include <iostream>
using namespace std;

struct EmptyStruct {};
class EmptyClass {};
struct CharStruct { char c; };
class CharClass { char c; };
class Base {
public:
int a;
};
struct Derived : Base {
public:
int b;
};

int main() {
EmptyClass *p;
Derived d;
Base &b = d;
cout << "sizeof empty struct " << sizeof(struct EmptyStruct) << '\n';
cout << "sizeof empty class " << sizeof(EmptyClass) << '\n';
cout << "sizeof Char struct " << sizeof(struct CharStruct) << '\n';
cout << "sizeof Char class " << sizeof(CharClass) << '\n';
cout << "sizeof pointer " << sizeof(p) << '\n';
cout << "sizeof the Base class " << sizeof(Base) << '\n';
cout << "sizeof the Derived class " << sizeof(Derived) << '\n';
cout << "sizeof the Derived through Base " << sizeof(b) << '\n';

return 0;
}

我的平台輸出如下,不管是空的 struct 或者空的 class 基本開銷就是 1,即使裡面放了一個 char 變數也還是 1,

1
2
3
4
5
6
7
8
sizeof empty struct              1
sizeof empty class 1
sizeof Char struct 1
sizeof Char class 1
sizeof pointer 8
sizeof the Base class 4
sizeof the Derived class 8
sizeof the Derived through Base 4

sizeof 資料結構對齊問題

現代的編譯器幾乎都會進行最佳化,所以有時候某資料結構佔用的 bytes 數可能不是你想像的,原因是因為編譯器會為了運行效能進行最佳化,如下列範例所示,

cpp-sizeof5.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// g++ cpp-sizeof5.cpp -o a.out
#include <iostream>
using namespace std;

struct CharChar { char c; char c2; };
struct CharCharInt { char c; char c2; int i; };
struct IntCharChar { int i; char c; char c2; };
struct CharIntChar { char c; int i; char c2; };
struct CharShortChar { char c; short s; char c2; };

int main() {
cout << "sizeof(CharChar) " << sizeof(CharChar) << '\n';
cout << "sizeof(CharCharInt) " << sizeof(CharCharInt) << '\n';
cout << "sizeof(IntCharChar) " << sizeof(IntCharChar) << '\n';
cout << "sizeof(CharIntChar) " << sizeof(CharIntChar) << '\n';
cout << "sizeof(CharShortChar) " << sizeof(CharShortChar) << '\n';

return 0;
}

我的平台輸出如下,值得注意的是 CharCharInt 手算的話應該為 6,但是編譯器進行最佳化時會變成 8,
而 CharIntChar 會因為順序關係而造成最佳化結果不同變成 12,
CharShortChar 手算的話應該為 4,但是編譯器進行最佳化時會變成 6,

1
2
3
4
5
sizeof(CharChar)       2
sizeof(CharCharInt) 8
sizeof(IntCharChar) 8
sizeof(CharIntChar) 12
sizeof(CharShortChar) 6

通常在跨平台或資料結構的網路通訊中會需要資料對齊,
那麼如果要一定讓它強制對齊的話呢?Windows 與 Linux / macOS 作法不同,
在 Linux / macOS 下是這樣做,要加上 __attribute__((__packed__)),加在前或後都可以,適用於 GCC 編譯器,

cpp-sizeof6.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// g++ cpp-sizeof6.cpp -o a.out
#include <iostream>
using namespace std;

struct __attribute__((__packed__)) CharChar {
char c;
char c2;
};

struct __attribute__((__packed__)) CharCharInt {
char c;
char c2;
int i;
};

struct IntCharChar {
int i;
char c;
char c2;
} __attribute__((__packed__));

struct CharIntChar {
char c;
int i;
char c2;
} __attribute__((__packed__)) charintchar;

typedef struct CharShortChar {
char c;
short s;
char c2;
} __attribute__((__packed__)) CharShortChar_t;

int main() {
charintchar.i = 123;
CharShortChar_t charshortchar;
cout << "sizeof(CharChar) " << sizeof(CharChar) << '\n';
cout << "sizeof(CharCharInt) " << sizeof(CharCharInt) << '\n';
cout << "sizeof(IntCharChar) " << sizeof(IntCharChar) << '\n';
cout << "sizeof(CharIntChar) " << sizeof(CharIntChar) << '\n';
cout << "sizeof(CharShortChar) " << sizeof(CharShortChar) << '\n';

return 0;
}

我的平台輸出如下,

1
2
3
4
5
sizeof(CharChar)       2
sizeof(CharCharInt) 6
sizeof(IntCharChar) 6
sizeof(CharIntChar) 6
sizeof(CharShortChar) 4

在 Windows 下是這樣做,#pragma pack 這寫法原本只適用於 Visual C++ 編譯器,但後來 GCC 為了相容性也加入了這個語法的支援,

cpp-sizeof7.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// g++ cpp-sizeof7.cpp -o a.out
#include <iostream>
using namespace std;

//#pragma pack(push)
//#pragma pack(1)
#pragma pack(push, 1)
struct CharChar { char c; char c2; };
struct CharCharInt { char c; char c2; int i; };
struct IntCharChar { int i; char c; char c2; };
struct CharIntChar { char c; int i; char c2; };
struct CharShortChar { char c; short s; char c2; };
#pragma pack(pop)

int main() {
cout << "sizeof(CharChar) " << sizeof(CharChar) << '\n';
cout << "sizeof(CharCharInt) " << sizeof(CharCharInt) << '\n';
cout << "sizeof(IntCharChar) " << sizeof(IntCharChar) << '\n';
cout << "sizeof(CharIntChar) " << sizeof(CharIntChar) << '\n';
cout << "sizeof(CharShortChar) " << sizeof(CharShortChar) << '\n';

return 0;
}

我的平台輸出如下,同上,

1
2
3
4
5
sizeof(CharChar)       2
sizeof(CharCharInt) 6
sizeof(IntCharChar) 6
sizeof(CharIntChar) 6
sizeof(CharShortChar) 4

有關資料結構對齊問題的詳細分享無法在本篇完整解釋以後再另文說明。

以上就是 C/C++ sizeof 的用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

sizeof operator - cppreference.com
https://en.cppreference.com/w/cpp/language/sizeof
c++ - what is the difference between __attribute__((__packed__)); and #pragma pack(1) - Stack Overflow
https://stackoverflow.com/questions/32208805/what-is-the-difference-between-attribute-packed-and-pragma-pack1

其它相關文章推薦
如果你想學習 C/C++ 相關技術,可以參考看看下面的文章,
C/C++ 新手入門教學懶人包
C/C++ typedef 用法與範例
C/C++ define 用法與範例