C Language
Typedef
수색…
소개
typedef
메커니즘을 사용하면 다른 유형의 별칭을 만들 수 있습니다. 새로운 유형을 만들지는 않습니다. 사람들은 typedef
를 사용하여 코드의 이식성을 향상시키고, 유형을 구조화하거나 유니온 화하는 별칭을 지정하거나 함수 (또는 함수 포인터) 유형의 별칭을 작성합니다.
C 표준에서 typedef
는 편의상 '저장소 클래스'로 분류됩니다. static
또는 extern
과 같은 스토리지 클래스가 나타날 수있는 곳에서 구문 적으로 발생합니다.
통사론
- typedef existing_name alias_name;
비고
Typedef의 단점
typedef
는 큰 C 프로그램에서 네임 스페이스를 오염시킬 수 있습니다.
typedef 구조체의 단점
또한 태그 이름이없는 typedef
구조체는 헤더 파일 간의 순서 관계를 불필요하게 부과하는 주요 원인입니다.
중히 여기다:
#ifndef FOO_H
#define FOO_H 1
#define FOO_DEF (0xDEADBABE)
struct bar; /* forward declaration, defined in bar.h*/
struct foo {
struct bar *bar;
};
#endif
이러한 정의에서는 typedefs
사용하지 않고 컴파일 단위가 foo.h
를 포함하여 FOO_DEF
정의에 도달 할 수 있습니다. foo
구조체의 bar
멤버를 참조 해제하려고 시도하지 않으면 bar.h
파일을 포함 할 필요가 없습니다.
Typedef 대 #define
#define
은 typedef
와 비슷하지만 다음과 같은 차이점이있는 다양한 데이터 유형의 별칭을 정의하는 데 사용되는 C 사전 프로세서 지시문입니다.
typedef
는#define
을 사용하여 값의 별칭을 정의하는 데만 사용할 수있는 유형에 기호 이름을 부여하는 것으로 제한됩니다.#define
문은 전처리#define
의해 처리되는 반면typedef
해석은 컴파일러에 의해 수행됩니다.#define cptr char *
다음에cptr a, b;
가cptr a, b;
typedef char *cptr;
과 동일하지 않습니다typedef char *cptr;
이어서cptr a, b;
.#define
사용하면b
는 일반char
변수이지만typedef
있는 포인터이기도합니다.
구조체 및 공용체에 대한 typedef
struct
별칭 이름을 지정할 수 있습니다.
typedef struct Person {
char name[32];
int age;
} Person;
Person person;
구조체를 선언하는 전통적인 방법과 비교할 때, 프로그래머는 struct
의 인스턴스를 선언 할 때마다 struct
를 가질 필요가 없습니다.
Person
( struct Person
과는 반대)이라는 이름은 최종 세미콜론까지 정의되어 있지 않습니다. 따라서 동일한 구조 유형에 대한 포인터를 포함해야하는 연결된 목록 및 트리 구조의 경우 다음 중 하나를 사용해야합니다.
typedef struct Person {
char name[32];
int age;
struct Person *next;
} Person;
또는:
typedef struct Person Person;
struct Person {
char name[32];
int age;
Person *next;
};
union
타입에 대한 typedef
의 사용은 매우 유사합니다.
typedef union Float Float;
union Float
{
float f;
char b[sizeof(float)];
};
이와 비슷한 구조는 float
값을 구성하는 바이트를 분석하는 데 사용될 수 있습니다.
typedef의 간단한 사용법
데이터 유형에 짧은 이름을 지정하는 경우
대신에:
long long int foo;
struct mystructure object;
하나는 사용할 수있다.
/* write once */
typedef long long ll;
typedef struct mystructure mystruct;
/* use whenever needed */
ll foo;
mystruct object;
이렇게하면 형식이 프로그램에서 여러 번 사용되는 경우 필요한 타이핑 작업이 줄어 듭니다.
이식성 향상
데이터 유형의 속성은 아키텍처에 따라 다릅니다. 예를 들어 int
는 한 구현에서는 2 바이트 유형이고 다른 구현에서는 4 바이트 유형이 될 수 있습니다. 프로그램을 올바르게 실행하려면 4 바이트 유형을 사용해야한다고 가정합니다.
한 가지 구현에서 int
의 크기를 2 바이트로, long
를 4 바이트로 지정합니다. 또 다른 방법은 int
의 크기를 4 바이트로, long
를 8 바이트로 지정합니다. 프로그램이 두 번째 구현을 사용하여 작성된 경우,
/* program expecting a 4 byte integer */
int foo; /* need to hold 4 bytes to work */
/* some code involving many more ints */
첫 번째 구현에서 프로그램을 실행하려면 모든 int
선언을 long
으로 변경해야합니다.
/* program now needs long */
long foo; /*need to hold 4 bytes to work */
/* some code involving many more longs - lot to be changed */
이를 방지하기 위해 typedef
를 사용할 수 있습니다.
/* program expecting a 4 byte integer */
typedef int myint; /* need to declare once - only one line to modify if needed */
myint foo; /* need to hold 4 bytes to work */
/* some code involving many more myints */
그런 다음 typedef
문만 전체 프로그램을 검사하는 대신 변경해야합니다.
<stdint.h>
헤더와 관련 <inttypes.h>
헤더는 다양한 크기의 정수에 표준 형식 이름 ( typedef
사용)을 typedef
하며, 고정 크기 정수가 필요한 최신 코드에서 이러한 이름이 가장 적합한 경우가 많습니다. 예를 들어, uint8_t
는 부호없는 8 비트 정수 유형입니다. int64_t
는 부호있는 64 비트 정수 유형입니다. uintptr_t
유형은 오브젝트에 대한 포인터를 보유하기에 충분히 큰 부호없는 정수 유형입니다. 이러한 유형은 이론적으로 선택 사항이지만 사용할 수없는 경우는 거의 없습니다. uint_least16_t
(최소 16 비트가있는 최소 부호없는 정수 유형) 및 int_fast32_t
(32 비트 이상의 가장 빠른 부호있는 정수 유형)와 같은 변형이 있습니다. 또한 intmax_t
및 uintmax_t
는 구현에서 지원하는 가장 큰 정수 유형입니다. 이러한 유형은 필수 항목입니다.
사용량을 지정하거나 가독성을 높이려면
데이터 집합에 특정 목적이있는 경우 typedef
를 사용하여 의미있는 이름을 지정할 수 있습니다. 또한 기본 유형이 변경되어야하는 데이터 속성이 변경되면 전체 프로그램을 검사하는 대신 typedef
문만 변경해야합니다.
함수 포인터 typedef
함수 포인터의 사용을 단순화하기 위해 typedef
를 사용할 수 있습니다. 우리 모두가 같은 서명을 가지고, 인자를 사용하여 다른 방법으로 어떤 것을 인쇄하는 몇 가지 함수가 있다고 상상해보십시오.
#include<stdio.h>
void print_to_n(int n)
{
for (int i = 1; i <= n; ++i)
printf("%d\n", i);
}
void print_n(int n)
{
printf("%d\n, n);
}
이제 typedef
를 사용하여 printer라는 명명 된 함수 포인터 유형을 만들 수 있습니다.
typedef void (*printer_t)(int);
이것은 하나의 int
인자를 취하고 아무것도 가지고 있지 않은 함수에 대한 포인터에 대해 printer_t
라는 이름의 타입을 생성합니다.이 타입은 우리가 위에있는 함수의 서명과 일치합니다. 그것을 사용하기 위해 우리는 생성 된 타입의 변수를 생성하고 문제의 함수 중 하나에 포인터를 할당합니다 :
printer_t p = &print_to_n;
void (*p)(int) = &print_to_n; // This would be required without the type
그런 다음 함수 포인터 변수가 가리키는 함수를 호출합니다.
p(5); // Prints 1 2 3 4 5 on separate lines
(*p)(5); // So does this
따라서 typedef
는 함수 포인터를 처리 할 때보다 간단한 구문을 허용합니다. 이것은 함수 포인터가 함수에 대한 인수와 같은 더 복잡한 상황에서 사용될 때 더욱 분명해진다.
정의 된 함수 포인터 유형없이 매개 변수로 함수 포인터를 사용하는 함수를 사용하는 경우 함수 정의는 다음과 같습니다.
void foo (void (*printer)(int), int y){
//code
printer(y);
//code
}
그러나 typedef
는 다음과 같습니다.
void foo (printer_t printer, int y){
//code
printer(y);
//code
}
마찬가지로 함수는 함수 포인터를 반환 할 수 있으며 typedef
를 사용하면 구문을 더 간단하게 만들 수 있습니다.
전형적인 예는 <signal.h>
의 signal
함수입니다. C 표준의 선언문은 다음과 같습니다.
void (*signal(int sig, void (*func)(int)))(int);
이것은 두 개의 인수를 취하는 함수입니다. int
와 인수를 int
로 취하고 아무 것도 반환하지 않는 함수에 대한 포인터이며 두 번째 인수와 같은 함수 포인터를 반환합니다.
함수 유형에 대한 포인터의 별칭으로 SigCatcher
유형을 정의한 경우 :
typedef void (*SigCatcher)(int);
다음을 사용하여 signal()
을 선언 할 수 있습니다.
SigCatcher signal(int sig, SigCatcher func);
전체적으로 이것은 (C 표준이 작업을 수행하기위한 유형을 정의하지 않았더라도) 이해하기가 더 쉽습니다. signal
함수는 두 개의 인수, 소요 int
와 SigCatcher
하고는 반환 SigCatcher
- SigCatcher
받는 함수에 대한 포인터입니다 int
인수를 아무것도 반환합니다.
함수 유형에 대한 포인터에 typedef
이름을 사용하면 수명이 더 typedef
, 나중에 코드를 유지 관리하는 다른 사람들에게 혼동을 줄 수 있으므로 신중하고 적절한 문서를 사용하십시오. 함수 포인터를 참조하십시오.