コンテンツ
1つ:ユニオンキーワード
ユニオンキーワード:スペースはユニオン内で共有され、ユニオン全体のサイズは内部の最大要素によって決定されます。
#include<stdio.h>
union un
{
int a;
char b;
// a和b共用一个空间,不过空间总大小由a决定
};
int main()
{
// a和b共用一个空间,不过空间总大小由a决定
printf("%d\n", sizeof(union un)); // 4
return 0;
}
共用体へのアクセスは構造体のアクセスと同様であり、。演算子または->ポインター演算子を使用できます。
union un x;
x.a = 10;
union un* p = &x;
p->a;
ユニオンのスペースレイアウトの問題:
和集合の空間は、ここで決定される最大の要素によって決定されます。4バイト、bはaの下位アドレスまたは上位アドレスを占有しますか?
変数がスペースを開くとき、変数は開かれた後にアドレスを持ち、このアドレスは多くのバイトの中で最小でなければなりません。
ユニオン変数のアドレスとユニオン内の最大要素のアドレスを出力して、次のことを確認してみましょう。
数値が同じであることを確認するのは難しくありません
bの場合、スペースを申請するとき、すべてのスペース申請は下位アドレスから上に割り当てられるため、bは最下位アドレスから開始します。つまり、内部メンバーbとユニオン自体によって開かれたスペースとAのアドレス値変数は同じです。
結論は:
組合のすべてのメンバーは同じ開始アドレスを持ち、それぞれが最初の要素です。
bは常にaの下位アドレスにあります!!!
ユニオンの空間分布を使用して、サイズの終わりを巧みに判断できます。
ここでは、バイナリシーケンスのセット0x 00 00 00 01をaに対応するスペースに保存する必要があります。このとき、4バイトのそれぞれにアドレスがあり、アドレスには高レベルと低レベルがあり、データは1です。バイトに対応するビット。分割する場合、データには上位ビットと下位ビットがあるため、2つのストレージスキームがあります。1つは上位アドレスに配置された上位ビット、もう1つは下位アドレスに配置された下位ビットです。上の図では、01は下位アドレスに配置されています。2番目のスキームは反対です。上の図の右側に示すように、bは常にaの下位アドレスにあるため、 01は上位アドレスに配置されます。上の図に示すように、bは1バイトを占めます。xb= 1赤いマーカーは、ストレージスキームが最初の場合は分割され、次にb = 1、2番目の場合はb = 0、最初のストレージスキームが分割されます。はリトルエンディアンのストレージルールであり、2番目はビッグエンディアンのストレージルールです。
コードが示すように:
#include<stdio.h>
union un
{
int a;
char b;
};
int main()
{
union un x;
x.a = 1;
if (x.b == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
注:ユニオンの全体のサイズは、ユニオン内の要素のサイズで割り切れる必要があります
#include<stdio.h>
union un
{
int a;
char b[5];
};
int main()
{
printf("%d\n", sizeof(union un)); // 8
return 0;
}
以前の知識によると、ユニオンスペースは最大の要素によって決定され、bのサイズは5です。理論的には、ユニオンのサイズは5ですが、ユニオンのサイズは8です。ユニオンは、要素の任意のサイズを分割できる必要があります
別のコードを見てください。
ユニオンとサイズエンドの対応を反映します。
#include<stdio.h>
union un
{
int i;
char a[4];
}*p, u;
int main()
{
p = &u;
p->a[0] = 0x39;
p->a[1] = 0x38;
p->a[2] = 0x37;
p->a[3] = 0x36;
printf("0x%x", p->i); //0x36373839
return 0;
}
2:列挙型キーワード
enum enumerationキーワードの機能:一連の定数を列挙し、内部定数をデータとして直接使用できます。列挙自体も新しいタイプまたは設計されたタイプです。つまり、列挙型を使用して変数を直接定義できます。 。次のように:
#include<stdio.h>
enum color
{
RED,
YELLOW,
BLACK,
GREEN,
BLUE
};
int main()
{
enum color c = RED;
printf("%d\n", RED); // 0
printf("%d\n", BLACK); // 2
printf("%d\n", BLUE); // 4
return 0;
}
列挙の本質は整数であり、変更できないリテラル値に対応しているため、RED、BLACK、およびBLUEは本当の意味での定数です。
列挙型が存在するのはなぜですか?
1:現実の世界では、コードに反映する必要のある関連する定数がたくさんあります。
2:定数を列挙すると、すべての定数の定数名は数字ではなく、英語の単語で直接表されるため、このように記述されたコードは自己記述的です。
列挙定数の設定:
最初の列挙定数の内容が特定の番号に割り当てられている場合、後続の列挙定数は1ずつインクリメントされ、分割してインクリメントすることもできます。
#include<stdio.h>
enum color
{
RED=10,
YELLOW,
BLACK=-9,
GREEN,
BLUE
};
int main()
{
enum color c = RED;
printf("%d\n", RED); // 10
printf("%d\n", YELLOW); // 11
printf("%d\n", BLACK); // -9
printf("%d\n", GREEN); // -8
printf("%d\n", BLUE); // -7
return 0;
}
3:typedefキーワード
必須:タイプの名前変更。
#include<stdio.h>
//(1)
// 对结构体类型进行重命名
typedef struct stu {
char name[16];
int age;
char sex;
}stu_t;
//(2)
//对unsigned int 重命名 u_int 简化
typedef unsigned int u_int;
//(3)
//对指针int*重命名
typedef int* int_p;
//(4)
typedef int a[10]; // 此刻a相当于一种数组类型
int main()
{
u_int x = 0;
int_p p = NULL;
stu_t s;
a b;
return 0;
}
タイプの名前変更により、よく理解されていない一部のデータタイプを単純化できます。
ただし、typedefの名前を簡単に変更できるわけではありません。ポインタまたは配列の名前を変更すると、使用時に一部の詳細が無視されます。たとえば、配列にはいくつの要素があり、タイプは何ですか、ポインターはどのタイプのポインターですか?過度のtypedefの本質は、実際には変装して邪魔なものですが、構造体でtypedefキーワードを使用することをお勧めします
typedefと#defineの違い
最初にコードを見てください:
このコードはtypedefを使用します
#include<stdio.h>
typedef int* int_p;
int main()
{
//int* a, b;
// 此时a为指针,b为int 整型类型
//int* a = NULL, b = 0; //可读性太差
int_p a, b;
// 此时a 和 b均为指针,等价于int* a, * b;
return 0;
}
typedef型の名前変更を一種の置換とは考えないでください。int_tをint*として直接理解することはできず、2つを直接置き換えることはできません。代わりに、int_tはまったく新しいタイプとして理解する必要があるため、*を最初に組み合わせるかbを最初に組み合わせるかは問題ありません。この*の型は、その後に定義されたすべての変数に有効になり、int_pは独立した型として使用されます。
#defineで再試行してください
#include<stdio.h>
#define ptr_t int*
int main()
{
ptr_t a, b, c;
//等价于
int* a, b, c;
//a为int*, b和c均为int;
return 0;
}
結論は:
typedefタイプの名前変更、必須のテキスト置換ではなく、新しい独立したタイプの形成
マクロ定義が行うことは、プレーンテキストの置換です
場合:
#include<stdio.h>
#define INT32 int
typedef int int32;
int main()
{
unsigned INT32 a;
//因为宏define是文本替换,所以INT32就相当于int,所以就是ungsigned int a;
//unsigned int32 b; 代码报错
return 0;
}
質問:typedef static int int32_tは機能しますか?
図からそれが不可能であることが容易にわかり、コンパイラはこの時点でエラーを出します。
32のキーワードの中に、5つのストレージタイプのキーワードがあります。
storagetypeキーワードには次の特徴があります。
ストレージキーワードを同時に表示することはできません。つまり、変数が定義されている場合、存在できるのは1つだけです。
したがって、typedefとstaticの2つのキーワードを同時に表示することはできないため、上記のコードはエラーを報告します。