티스토리 뷰
반응형
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(¤tPrice_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", ¤tPrice_st);
// call-by-value 값 출력
print_value(currentPrice_st);
// call-by-reference 값 출력
print_reference(¤tPrice_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(¤tPrice_st);
변수에 대한 주소는 변수앞에 & 를 붙여서 만든다고 설명드렸지요. 그래서 여기서도 ¤tPrice_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 = ¤tPrice_st;
// currentPrice_st 크기와 메모리 주소 출력
printf("currentPrice_st 주소[%p]\n", ¤tPrice_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 = ¤tPrice_st;
- 이전 강의에서 설명드렸는데 포인터 변수는 단독(버퍼없이)으로는 사용할 수 없다고 말씀드렸습니다.
ptrPrice_st = ¤tPrice_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
링크
TAG
- strcpy
- 배열
- memcpy
- sharetravelplan
- #ifdef
- Member
- array
- IPC
- c프로그램
- Call-by-value
- 의유
- #include
- 재고
- #define
- String
- C언어
- 포인터
- 전처리기
- 소켓
- 리눅스
- GCC
- struct
- 파라메타
- 문자열
- Call-By-Reference
- Linux
- memset
- Clang
- Pointer
- While
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함