안녕하세요 여러분, 오늘 저는 C 언어의 사용자 정의 유형인 구조, 열거형, 공용체는 물론 이전에 알지 못했을 수도 있는 구조 메모리 정렬 및 비트 세그먼트와 같은 지식 포인트를 여러분과 공유하고 싶습니다! ! !
1. 구조
구조체는 멤버 변수라고 불리는 값의 집합입니다. 구조체의 각 멤버는 다양한 유형의 변수가 될 수 있습니다.
구조 선언: 예를 들어 학생을 설명하는 경우:
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢
이는 학생의 구조 유형을 성공적으로 정의합니다.
특수 구조체 선언:
구조체 선언 시 불완전하게 선언될 수 있습니다.
//匿名结构体类型:结构在声明的时候省略掉了结构体标签
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], *p;
참고: // 위 코드를 기준으로 볼 때 다음 코드는 합법인가요?
p = &x;
컴파일러는 위의 두 선언을 완전히 다른 두 유형으로 처리합니다.
그러니 불법입니다.
구조의 자체 참조
//正确的自引用
struct Node
{
int data;
struct Node* next;
};
//错误的自引用,促使无法确定结构体的大小
struct Node
{
int data;
struct Node next;
};
해결책:
typedef struct Node
{
int data;
struct Node* next;
}Node;
구조 변수 정의 및 초기화
구조체 타입을 사용하면 변수를 정의하는 방법이 실제로 매우 간단합니다.
struct Point
{
int x;
int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//初始化:定义变量的同时赋初值。
struct Point p3 = {
x, y};
struct Stu //类型声明
{
char name[15];//名字
int age; //年龄
};
struct Stu s = {
"zhangsan", 20};//初始化
struct Node
{
int data;
struct Point p;
struct Node* next;
}n1 = {
10, {
4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {
20, {
5, 6}, NULL};//结构体嵌套初始化
구조 메모리 정렬:
구조의 기본 사용을 마스터했습니다.
이제 구조의 크기를 계산하는 문제를 살펴보겠습니다.
이것은 또한 특히 인기 있는 지식 포인트입니다: 구조 메모리 정렬
아래 코드를 살펴보면 전체 구조의 크기에 대한 첫인상은 어떻습니까?
struct S1
{
char c1;
int i;
char c2;
};
두 문자에 정수 하나를 더하면 크기가 6바이트가 되어서는 안 되는데, 실행하면 왜 12바이트가 되는지, 상황은 어떤가요? 여기서 우리는 학습 구조 기억 정렬에 대한 지식을 이해해야 합니다!
먼저 구조의 메모리 정렬 규칙을 열어 보겠습니다.
- 첫 번째 멤버는 구조 변수의 오프셋 0에 있습니다.
- 다른 멤버 변수는 특정 숫자(정렬 번호)의 정수 배수인 주소에 정렬되어야 합니다.
정렬 번호 = 컴파일러의 기본 정렬 번호와 멤버 크기 중 더 작은 것입니다.
VS의 기본값은 8입니다.- 구조체의 전체 크기는 최대 정렬 번호의 정수배입니다(각 멤버 변수에는 정렬 번호가 있음).
- 구조가 중첩된 경우 중첩된 구조는 자체 최대 정렬 번호의 정수 배수로 정렬되고
구조의 전체 크기 모든 최대 정렬 번호(중첩 구조의 정렬 번호 포함)의 정수 배수입니다.
이 그림을 보면 구조의 메모리 정렬이 무엇인지 대략적으로 이해할 수 있을 것 같고 크기가 12인 이유도 이해할 수 있을 것 같습니다!
중첩된 구조의 크기를 살펴보겠습니다.
struct S4
{
char c1;
struct S1 s1;
double d;
};
printf("%d\n", sizeof(struct S4));
분석을 살펴보겠습니다.
구조 메모리 정렬이 있는 이유는 다음과 같습니다.
대부분의 참고 자료에는 다음과 같이 나와 있습니다.
- 플랫폼 이유(이식 이유):
모든 하드웨어 플랫폼이 모든 주소의 모든 데이터에 액세스할 수 있는 것은 아닙니다. 일부 하드웨어 플랫폼은 특정 주소에서 특정 유형의 데이터만 가져올 수 있습니다
. 그렇지 않으면 하드웨어 예외가 발생합니다.
- 성능 이유:
데이터 구조(특히 스택)는 가능할 때마다 자연스러운 경계에 정렬되어야 합니다.
그 이유는 정렬되지 않은 메모리에 액세스하려면 프로세서가 두 번의 메모리 액세스를 수행해야 하지만 정렬된 메모리 액세스에는 한 번의 액세스만 필요하기 때문입니다
.
구조를 디자인할 때 정렬을 만족시키는 것뿐만 아니라 공간을 절약해야 하는데,
공간을 덜 차지하는 멤버들을 최대한 모아야 한다.
위의 메모리 정렬 질문에는 기본 정렬 번호가 언급되어 있으며 수정이 가능합니다!
우리는 #pragma 전처리 지시문을 보았고 여기서는 이를 다시 사용하여 기본 정렬 번호를 변경합니다.
#include <stdio.h>
#pragma pack(1)//设置默认对齐数为8
struct S2
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
//在这个区间里面默认对齐数就是1啦
2. 포지션 세그먼트
구조에 대해 이야기한 후에는 비트 세그먼트를 구현하는 구조의 능력에 대해 이야기해야 합니다.
비트
세그먼트 정의 비트 세그먼트의 선언과 구조는 유사하지만 두 가지 차이점이 있습니다:
1. 비트 세그먼트의 구성원은 int, unsigned int 또는 signed int여야 합니다.
2. 비트 필드의 멤버 이름 뒤에는 콜론과 숫자가 있습니다.
다음은 비트 세그먼트의 정의입니다.
struct A
{
int _a:2;//_a占2个比特位
int _b:5;
int _c:10;
int _d:30;
};
A는 비트 세그먼트 유형입니다.
세그먼트 A의 크기는 얼마입니까? 콜론 뒤의 비트는 해당 변수가 차지하는 비트입니다.
비트 세그먼트에 대한 메모리 할당:
- 비트 필드의 멤버는 int unsigned int signed int 또는 char(정수 계열에 속함) 유형일 수 있습니다.
- 비트 필드의 공간은 필요에 따라 4바이트(int) 또는 1바이트(char)로 할당됩니다.
- 비트 세그먼트에는 많은 불확실성이 포함됩니다. 비트 세그먼트는 크로스 플랫폼이 아닙니다. 이식성에 초점을 맞춘 프로그램은 비트 세그먼트 사용을 피해야 합니다.
struct S
{
char a:3;
char b:4;
char c:5;
char d:4;
};
int main()
{
struct S s = {
0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;}
비트 세그먼트와 관련된 플랫폼 간 문제
1. int 비트 필드가 부호 있는 숫자로 간주되는지, 부호 없는 숫자로 간주되는지는 정의되지 않습니다.
2. 비트 필드의 최대 비트 수를 결정할 수 없습니다. (16비트 머신의 최대 개수는 16이고, 32비트 머신의 최대 개수는 32이므로 27로 표기됩니다. 이는
16비트 머신에서는 문제를 발생시킵니다. 3
. 비트 세그먼트는 메모리에서 왼쪽에서 오른쪽으로 할당되거나 오른쪽에서 왼쪽으로 아직 정의되지 않았습니다.
4. 구조체에 두 개의 비트 필드가 포함되어 있고 두 번째 비트 필드의 멤버가 더 크고 나머지 비트를 수용할 수 없는 경우 첫 번째 비트 필드에서는 나머지
비트를 버릴지 아니면 사용할지 확실하지 않습니다.
비트 필드에는 데이터를 보낼 때 데이터 패키징에 특정 응용 프로그램이 있습니다.
3. 열거
열거란 이름에서 알 수 있듯이 항목을 하나씩 열거하는 것을 의미합니다.
가능한 값을 하나씩 나열해 보세요.
예를 들어 실생활에서는
월요일부터 일요일까지 일주일에 7일로 제한되어 있으며 하나씩 나열할 수 있습니다.
성별에는 남성, 여성, 기밀이 포함되며 하나씩 나열할 수도 있습니다.
enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Color//颜色
{
RED,
GREEN,
BLUE
};
위에서 정의한 enum Day와 enum Color는 모두 열거형이다. {}의 콘텐츠는 열거형 상수라고도 하는 열거형의 가능한 값입니다(수정할 수 없음).
이러한 가능한 값은 모두 유효하며 기본적으로 0부터 시작하여 한 번에 1씩 증가합니다.
물론 정의 시 초기값을 지정할 수도 있습니다. 예를 들어
enum Color//颜色
{
RED=1,
GREEN=2,
BLUE=4
};
열거된 유형이 있을 수 있으므로 고유한 장점이 있어야 합니다.
코드의 가독성 및 유지 관리 용이성 향상
#define으로 정의된 식별자와 비교하여 열거형에는 유형 검사가 더 엄격합니다.
명명 오염(캡슐화)을 방지
하고 디버깅을 용이하게 하며, 사용이 간편
하고 한 번에 여러 상수를 정의할 수 있습니다.
열거형 사용:
enum Color//颜色
{
RED=1 ,
GREEN = 2,
BLUE = 4
};
int main()
{
//printf("%d\n", sizeof(union Un1));
enum Color col=RED ;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异,枚举常量实质就是整型。
col = 3.8;
printf("%d", col);
}
4. 연합(공통)체
공용체의 멤버는 동일한 메모리 공간을 공유하므로 공용체 변수의 크기는 최소한 가장 큰 멤버의 크기 이상이어야 합니다(왜냐하면 공용체는 최소한 가장 큰 멤버를 저장할 수 있어야 하기 때문입니다).
union Un
{
int i;
char c;
};
union Un un;
int main()
{
printf("%p\n", &(un.i));
printf("%p\n", &(un.c));
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i);
}
조합 규모 계산
Union의 크기는 최소한 가장 큰 구성원의 크기입니다.
최대 멤버 크기가 최대 정렬 번호의 정수 배수가 아닌 경우 최대 정렬 번호의 정수 배수로 정렬되어야 합니다.
union Un1
{
char c[5];
int i;
};
int main()
{
printf("%d\n", sizeof(union Un1));
}
분석: 공용체의 크기는 먼저 가장 큰 멤버의 크기이고, c[5]는 5바이트를 차지하고, 배열 c[]의 각 요소 크기는 1이며, vs의 기본 정렬 번호는 8이고, 그 다음은 정렬 번호는 1이고 i는 4바이트를 차지하며 vs의 기본 정렬 번호는 8이고 정렬 번호는 4이고 최대 정렬 번호는 4이며 정수로 정렬된 후 공용체의 크기는 8입니다. 4의 배수
컨소시엄의 적용:
여러 항목이 포함된 구조를 정의할 때 다양한 항목의 특정 속성을 통합 유형으로 정의할 수 있으므로 공간이 크게 절약됩니다! ! !
오늘의 내용은 여기에 공유합니다. 모두에게 도움이 되기를 바라며 함께 발전해 갑시다! ! !