티스토리 뷰

반응형

1) 목표

  • 구조체의 크기 알아보기
  • #pragma pack 에 대해서 이해하기
  • 구조체를 함수 파라메타로 사용하기
  • 구조체 포인터인 경우 멤버접근 방법 알아보기

2) 설명

// 구조체의 크기
sizeof(CURRENT_PRICE_ST);

// call-by-value로 구조체 사용하기
void print_value(CURRENT_PRICE_ST valuePrice) {
    printf("주식코드:[%s]\n", valuePrice.code);
    ...
}

// call-by-reference로 구조체 사용하기
void print_reference(CURRENT_PRICE_ST *ptrPrice) {
    printf("주식코드:[%s]\n", ptrPrice->code);
    ...
}
  • 구조체의 크기도 sizeof 연산자로 구할수 있습니다.
    정의된 구조체의 크기
    sizeof(CURRENT_PRICE_ST);
    선언된 구조체의 크기
    sizeof(currentPrice_st);
  • call-by-value는 구조체를 그대로 받아서 같은 방식으로 사용합니다.
    구조체 변수명에 . 멤버명으로 사용합니다.
  • call-by-reference는 구조체에 대한 포인터로 받아서 사용합니다.
    이때 구조체 멤버는 구조체 포인터명에 ->멤버명으로 사용하면 됩니다.
    code멤버에 대한 접근은 ptrPrice->code로 사용합니다.
    또한 호출하는곳에서는 변수의 포인터처럼 & 를 붙여서 호출하면 포인터를 넘겨줍니다.
    print_reference(&currentPrice_st);

3-1) 크기 예제 프로그램

    ▶ vi struct4.c

#include <stdio.h>

// 주식 현재가 struct 의 새로운 타입을 정의
typedef struct {
    char code[10];          // 주식코드
    char name[80];          // 주식명
    int currentPrice;       // 현재가
    int startPrice;         // 시가
    int highPrice;          // 고가
    int lowPrice;           // 저가
    double qty;             // 거래량
} CURRENT_PRICE_ST;

void main() {
    CURRENT_PRICE_ST currentPrice_st = {"A005930", "삼성전자", 61000, 60500, 62000, 60300, 1234500.0};

    // 정의된 CURRENT_PRICE_ST의 크기
    printf("CURRENT_PRICE 크기[%ld]\n", sizeof(CURRENT_PRICE_ST));

    // currentPrice_st 크기
    printf("currentPrice_st 크기[%ld]\n", sizeof(currentPrice_st));
}

    ▶ 컴파일/실행

~/c-lecture (master ✘)✭ ᐅ gcc -o struct4 struct4.c
~/c-lecture (master ✘)✭ ᐅ ./struct4
CURRENT_PRICE 크기[120]
currentPrice_st 크기[120]
~/c-lecture (master ✘)✭ ᐅ

    ▶ 분석

  • typedef로 정의된 CURRENT_PRICE_ST로 크기를 구하거나 선언된 currentPrice_st로 구해도 값은 동일합니다.
  • CURRENT_PRICE_ST의 멤버의 각각을 sizeof()로 구해보면 
    code[10]:10바이트
    code[80]:80바이트
    int : 4바이트 * 4개 (currentPrice, startPrice, highPrice, lowPrice) : 16바이트
    double : 8바이트
    모두 합해보면 114입니다. 그런데 sizeof()로 출력해 보면 120이 출력된걸 보실수 있습니다.
    구조체를 선언할때 시스템에서는 구조체중 가장 크기가 큰 타입 (여기서는 double qty)의 배수로 메모리를 할당해 줍니다. 그래서 차이가 생깁니다. 
    이렇게 차이가 나면 개발시 구조체를 사용할때 문제가 발생합니다.
    그럼 이런 차이를 없애는 방법은 어떻게 하면 될까요?

3-2) #pragma pack 예제 프로그램

    ▶ vi struct5.c

#include <stdio.h>

#pragma pack(1)

// 주식 현재가 struct 의 새로운 타입을 정의
typedef struct {
    char code[10];          // 주식코드
    char name[80];          // 주식명
    int currentPrice;       // 현재가
    int startPrice;         // 시가
    int highPrice;          // 고가
    int lowPrice;           // 저가
    double qty;             // 거래량
} CURRENT_PRICE_ST;

void main() {
    CURRENT_PRICE_ST currentPrice_st = {"A005930", "삼성전자", 61000, 60500, 62000, 60300, 1234500.0};

    // 정의된 CURRENT_PRICE_ST의 크기
    printf("CURRENT_PRICE 크기[%ld]\n", sizeof(CURRENT_PRICE_ST));

    // currentPrice_st 크기
    printf("currentPrice_st 크기[%ld]\n", sizeof(currentPrice_st));
}

    ▶ 컴파일/실행

~/c-lecture (master ✘)✭ ᐅ gcc -o struct5 struct5.c
~/c-lecture (master ✘)✭ ᐅ ./struct5
CURRENT_PRICE 크기[114]
currentPrice_st 크기[114]
~/c-lecture (master ✘)✭ ᐅ

    ▶ 분석

  • 실행을 보시면 114가 출력된걸 보실 수 있습니다.
  • #pragma pack(1)
    struct문의 가장 큰 타입의 크기로 메모리가 할당되는것을  1바이트 단위로 할당하라는 명령어 입니다.
    개발중에 struct를 정의를 정확한 크기를 사용하실 경우 #pragma pack(1) 를 넣고 작업하시기 바랍니다.

3-3) 함수 예제 프로그램

    ▶ vi struct6.c

#include <stdio.h>

#pragma pack(1)

// 주식 현재가 struct 의 새로운 타입을 정의
typedef struct {
    char code[10];          // 주식코드
    char name[80];          // 주식명
    int currentPrice;       // 현재가
    int startPrice;         // 시가
    int highPrice;          // 고가
    int lowPrice;           // 저가
    double qty;             // 거래량
} CURRENT_PRICE_ST;

// call-by-value로 구조체 사용하기
void print_value(CURRENT_PRICE_ST valuePrice) {
    printf("--- print_value(%p) ---\n", &valuePrice);       // 메모리주소 출력
    printf("주식코드:[%s]\n", valuePrice.code);
    printf("주식명  :[%s]\n", valuePrice.name);
    printf("현재가  :[%d]\n", valuePrice.currentPrice);
    printf("시가    :[%d]\n", valuePrice.startPrice);
    printf("고가    :[%d]\n", valuePrice.highPrice);
    printf("저가    :[%d]\n", valuePrice.lowPrice);
    printf("거래량  :[%.0f]\n", valuePrice.qty);
}

// call-by-reference로 구조체 사용하기
void print_reference(CURRENT_PRICE_ST *ptrPrice) {
    printf("--- print_reference(%p) ---\n", ptrPrice);  // 메모리주소 출력
    printf("주식코드:[%s]\n", ptrPrice->code);
    printf("주식명  :[%s]\n", ptrPrice->name);
    printf("현재가  :[%d]\n", ptrPrice->currentPrice);
    printf("시가    :[%d]\n", ptrPrice->startPrice);
    printf("고가    :[%d]\n", ptrPrice->highPrice);
    printf("저가    :[%d]\n", ptrPrice->lowPrice);
    printf("거래량  :[%.0f]\n", ptrPrice->qty);
}

void main() {
    // struct _tagCurrentPrice의 선언
    CURRENT_PRICE_ST currentPrice_st = {"A005930", "삼성전자", 61000, 60500, 62000, 60300, 1234500.0};

    // currentPrice_st 크기와 메모리 주소 출력
    printf("currentPrice_st 주소[%p]\n", &currentPrice_st);

    // call-by-value 값 출력
    print_value(currentPrice_st);

    // call-by-reference 값 출력
    print_reference(&currentPrice_st);
}

    ▶ 컴파일/실행

~/c-lecture (master ✘)✭ ᐅ gcc -o struct6 struct6.c
~/c-lecture (master ✘)✭ ᐅ ./struct6
currentPrice_st 주소[0x7fff83553cb0]
--- print_value(0x7fff83553c30) ---
주식코드:[A005930]
주식명  :[삼성전자]
현재가  :[61000]
시가    :[60500]
고가    :[62000]
저가    :[60300]
거래량  :[1234500]
--- print_reference(0x7fff83553cb0) ---
주식코드:[A005930]
주식명  :[삼성전자]
현재가  :[61000]
시가    :[60500]
고가    :[62000]
저가    :[60300]
거래량  :[1234500]
~/c-lecture (master ✘)✭ ᐅ

    ▶ 분석

  • 구조체의 내용을 출력하는 함수를 call-by-value, call-by-reference로 호출합니다.
  • call-by-value 방식
    print_value(currentPrice_st);
    출력된 내용을 보시면 이전 강의에서 설명드린대로 메모리 주소가 다릅니다.
    currentPrice_st 주소와 print_value() 주소가 다른 이유는 call-by-value방식은 함수가 호출될때 파라메타로 받은 변수를 새롭게 메모리가 할당됩니다. 즉, currentPrice_st  의 크기 114바이트 만큼 메모리가 새롭게 할당됩니다.
    개발을 하다 보면 수백,수천되는 구조체를 정의하고 사용하는 경우가 많습니다. 그럼 이렇게 call-by-value로 호출을 하면 함수가 호출될때 마다 구조체의 크기 만큼 메모리가 할당되어서 상당히 비효율적이 됩니다.
    이런 이유도 포인터를 사용하는 이유중 하나입니다.
  • call-by-reference 방식
    print_reference(&currentPrice_st);
    변수에 대한 주소는 변수앞에 & 를 붙여서 만든다고 설명드렸지요. 그래서 여기서도 &currentPrice_st로 파라메타를 넘겨줍니다.
    출력에서 알수 있듯이 currentPrice_st 주소와 print_reference() 주소가 같은걸 알수 있습니다.
    call-by-value 방식과 다르게 call-by-reference에서는 구조체 크기 만큼 메모리 할당이 일어나지 않습니다.
    currentPrice_st의 메모리를 포인터로 바로 사용하기 때문입니다.
    이때 구조체 멤버를 접근할때는 -> 를 사용합니다.
  • 구조체의 멤버 접근은 구조체 변수명 . 멤버명이고
    구조체의 포인터 멤버 접근은 구조체 변수명->멤버명 입니다.

3-4) 함수 예제 프로그램2

    ▶ vi struct7.c

#include <stdio.h>

#pragma pack(1)

// 주식 현재가 struct 의 새로운 타입을 정의
typedef struct {
    char code[10];          // 주식코드
    char name[80];          // 주식명
    int currentPrice;       // 현재가
    int startPrice;         // 시가
    int highPrice;          // 고가
    int lowPrice;           // 저가
    double qty;             // 거래량
} CURRENT_PRICE_ST;

// call-by-value로 구조체 사용하기
void print_value(CURRENT_PRICE_ST valuePrice) {
    printf("--- print_value(%p) ---\n", &valuePrice);       // 메모리주소 출력
    printf("주식코드:[%s]\n", valuePrice.code);
    printf("주식명  :[%s]\n", valuePrice.name);
    printf("현재가  :[%d]\n", valuePrice.currentPrice);
    printf("시가    :[%d]\n", valuePrice.startPrice);
    printf("고가    :[%d]\n", valuePrice.highPrice);
    printf("저가    :[%d]\n", valuePrice.lowPrice);
    printf("거래량  :[%.0f]\n", valuePrice.qty);
}

// call-by-reference로 구조체 사용하기
void print_reference(CURRENT_PRICE_ST *ptrPrice) {
    printf("--- print_reference(%p) ---\n", ptrPrice);  // 메모리주소 출력
    printf("주식코드:[%s]\n", ptrPrice->code);
    printf("주식명  :[%s]\n", ptrPrice->name);
    printf("현재가  :[%d]\n", ptrPrice->currentPrice);
    printf("시가    :[%d]\n", ptrPrice->startPrice);
    printf("고가    :[%d]\n", ptrPrice->highPrice);
    printf("저가    :[%d]\n", ptrPrice->lowPrice);
    printf("거래량  :[%.0f]\n", ptrPrice->qty);
}

void main() {
    // struct _tagCurrentPrice의 선언
    CURRENT_PRICE_ST currentPrice_st = {"A005930", "삼성전자", 61000, 60500, 62000, 60300, 1234500.0};
    // 포인터 변수
    CURRENT_PRICE_ST *ptrPrice_st = &currentPrice_st;

    // currentPrice_st 크기와 메모리 주소 출력
    printf("currentPrice_st 주소[%p]\n", &currentPrice_st);
    printf("    ptrPrice_st 주소[%p]\n", ptrPrice_st);

    // call-by-value 값 출력
    print_value(currentPrice_st);

    // call-by-reference 값 출력
    print_reference(ptrPrice_st);
}

    ▶ 컴파일/실행

~/c-lecture (master ✘)✭ ᐅ gcc -o struct7 struct7.c
~/c-lecture (master ✘)✭ ᐅ ./struct7
currentPrice_st 주소[0x7ffe4f50e980]
    ptrPrice_st 주소[0x7ffe4f50e980]
--- print_value(0x7ffe4f50e8f0) ---
주식코드:[A005930]
주식명  :[삼성전자]
현재가  :[61000]
시가    :[60500]
고가    :[62000]
저가    :[60300]
거래량  :[1234500]
--- print_reference(0x7ffe4f50e980) ---
주식코드:[A005930]
주식명  :[삼성전자]
현재가  :[61000]
시가    :[60500]
고가    :[62000]
저가    :[60300]
거래량  :[1234500]
~/c-lecture (master ✘)✭ ᐅ

    ▶ 분석

  • 구조체의 포인터 변수를 선언과 동시에 버퍼 주소를 할당합니다.
...
    // 포인터 변수
    CURRENT_PRICE_ST *ptrPrice_st = &currentPrice_st;
  • 이전 강의에서 설명드렸는데 포인터 변수는 단독(버퍼없이)으로는 사용할 수 없다고 말씀드렸습니다.
    ptrPrice_st = &currentPrice_st; 로 currentPrice_st의 주소를 ptrPrice_st에 할당합니다.
    그래서 여기서는 currentPrice_st가 포인터변수의 버퍼입니다. 114바이트 크기의 버퍼.
  • 출력을 보시면 ptrPrice_st값이 같은걸 알 수 있습니다.
  • 포인터의 중요한 개념이므로 다시 한번 강조해서 설명드립니다.
    포인터 변수는 항상 버퍼의 주소를 할당 받아서 사용합니다. 단독으로는 사용하실 수 없습니다.
반응형

'리눅스 C-언어 초급과정' 카테고리의 다른 글

19. #include,#define,#ifdef ..  (0) 2022.11.23
18. 구조체 중첩  (0) 2022.11.21
16. 구조체(struct)  (0) 2022.11.21
15. 문자열(배열) 다루기  (0) 2022.11.17
14. 함수 파라메타 유형  (0) 2022.11.17
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함