1.1 構造体の型宣言
構造体とはメンバー変数と呼ばれる値の集合です。構造体の各メンバーは異なる型の変数にすることができます
1.2 構造体の宣言
struct Stu //Stu是结构体类型
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢
ここで、VS コンパイラでのセミコロンの入力を終了します。構造体は付属しているので、心配しないでください。
1.3 匿名構造型
匿名構造タイプは 1 回限りのアイテムとして理解でき、使い切ると使用できなくなります。
struct
{
int a;
char b;
float c;
}s1;
struct
{
char c;
int a;
double d;
}* ps;
int main()
{
ps = &s1;
return 0;
}
このコードでは、構造体の型が省略されていることがわかります。
警告: コンパイラはこのコードを 2 つの完全に異なるタイプとして扱うため、不正です。
1.4 構造体の自己参照
//错误代码示例
struct Node
{
int data;
struct Node next;
};
//正确代码
struct Node
{
int data;
struct Node* next;
};
このタイプの自己参照は不正です。タイプは Node で、独自のメンバーも含まれています。次は決して終了しないコードです。
1.5 構造メモリの調整
struct s1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));
まず、構造の配置ルールをマスターします。
1. 最初のメンバは、構造体変数からのオフセットが 0 のアドレスにあります。
2. その他のメンバ変数は、ある数値(アライメント番号)の整数倍のアドレスにアライメントされている必要があります。
アライメント = コンパイラのデフォルトのアライメントとメンバー サイズの小さい値。
VS のデフォルト値は 8
3 です。構造体の合計サイズは、最大アライメントの整数倍です (各メンバー変数にはアライメントがあります)。
4. 構造体がネストされている場合、ネストされた構造体はそれ自体の最大アライメント数の整数倍にアライメントされ、
構造全体のサイズは最大アライメント数 (ネストした構造体のアライメント数を含む) に等しくなります。。
なぜメモリアライメントが存在するのでしょうか?
ほとんどの参考文献には次のようなことが書かれています。
1. プラットフォームの理由 (移植の理由):
すべてのハードウェア プラットフォームが任意のアドレスのデータにアクセスできるわけではありません。一部のハードウェア プラットフォームは、特定のアドレスの特定の特別なアドレスにのみアクセスできます。
特定のタイプのデータが存在しない場合、ハードウェア例外がスローされます。
2. パフォーマンス上の理由:
データ構造 (特にスタック) は、できる限り自然な境界上に配置する必要があります。
その理由は、アライメントされていないメモリにアクセスするには、プロセッサが 2 回のメモリ アクセスを行う必要があるのに対し、アライメントされたメモリ アクセスには 1 回だけ必要であるためです。
聞く。
一般的に:
構造の記憶の調整は、空間と時間を交換する実践です。
したがって、最終的な sizeof は 12 です
1.6 デフォルトのアライメント番号を変更する
之前我们见过了 #pragma 这个预处理指令,这里我们再次使用,可以改变我们的默认对齐数
#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}
结论:
结构在对齐方式不合适的时候,我么可以自己更改默认对齐数
1.7结构体传参
struct S
{
int data[1000];
int num;
};
struct S s = {
{1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print1(s); //传结构体
print2(&s); //传地址
return 0;
}
上面的 print1 和 print2 函数哪个好些?
答案是:首选print2函数。
原因:
函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的
下降。
结论:
结构体传参的时候,要传结构体的地址