수색…


소개

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

#definetypedef 와 비슷하지만 다음과 같은 차이점이있는 다양한 데이터 유형의 별칭을 정의하는 데 사용되는 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 문만 전체 프로그램을 검사하는 대신 변경해야합니다.

C99

<stdint.h> 헤더와 관련 <inttypes.h> 헤더는 다양한 크기의 정수에 표준 형식 이름 ( typedef 사용)을 typedef 하며, 고정 크기 정수가 필요한 최신 코드에서 이러한 이름이 가장 적합한 경우가 많습니다. 예를 들어, uint8_t 는 부호없는 8 비트 정수 유형입니다. int64_t 는 부호있는 64 비트 정수 유형입니다. uintptr_t 유형은 오브젝트에 대한 포인터를 보유하기에 충분히 큰 부호없는 정수 유형입니다. 이러한 유형은 이론적으로 선택 사항이지만 사용할 수없는 경우는 거의 없습니다. uint_least16_t (최소 16 비트가있는 최소 부호없는 정수 유형) 및 int_fast32_t (32 비트 이상의 가장 빠른 부호있는 정수 유형)와 같은 변형이 있습니다. 또한 intmax_tuintmax_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 함수는 두 개의 인수, 소요 intSigCatcher 하고는 반환 SigCatcher - SigCatcher 받는 함수에 대한 포인터입니다 int 인수를 아무것도 반환합니다.

함수 유형에 대한 포인터에 typedef 이름을 사용하면 수명이 더 typedef , 나중에 코드를 유지 관리하는 다른 사람들에게 혼동을 줄 수 있으므로 신중하고 적절한 문서를 사용하십시오. 함수 포인터를 참조하십시오.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow