C언어 가변인수에 관한 질문입니다.
글쓴이: loopinger / 작성시간: 수, 2021/06/23 - 1:47오전
아래와 같은 코드를 실행할 경우에 대한 결과값은
{0, 10, 0, 20, 0, 30} 과 같은 결과가 나옵니다.
제 생각에 컴퓨터가 이전과 달리 64bit 운영체제로 변경되면서
int형은 4byte를 차지하지만 메모리는 8byte를 차지하기 때문에
8byte공간에 4byte를 차지하기 때문이라는 생각이듭니다.
int형을 모두 __int64 로 바꾸면
p[0], p[1], p[2]가 {10, 20, 30}이 나오는 것은 확인하였지만
결론적으로 4byte공간만 사용하고 싶은데
8byte공간을 사용하고 있는 경우라고 생각이 들어서
메모리적으로 낭비라는 생각이 듭니다.
정말로 4byte 공간만 사용하는 방법이 있을까요?
혹은 제가 생각한 부분중 틀린 부분이 있나요?
#include <stdio.h> void test(int num, ...); int main(void) { int a=10, b=20, c=30; test(1, a, b, c); test(2, a, b, c); test(3, a, b, c); test(4, a, b, c); test(5, a, b, c); test(6, a, b, c); return 0; } void test(int num, ...) { int* p=NULL; p=&num + 1; if(num==1) { printf("%d \n", p[0]); } else if (num==2) { printf("%d \n", p[1]); } else if (num==3) { printf("%d \n", p[2]); } else if (num==4) { printf("%d \n", p[3]); } else if (num==5) { printf("%d \n", p[4]); } else if (num==6) { printf("%d \n", p[5]); } }
Forums:
...
가변인자를 사용하는 함수는 인자를 모두 스택에 넣어야 하고 꺼낼 때도 스택에서 하나씩 꺼내야 하기 때문에 컴파일러가 최적화를 하기 어렵습니다. 이게 무슨 얘기냐 하면, 가변인자를 사용하는 시점에서 이미 최적화는 어느 정도 포기하고 그 대신 코드 사이즈 혹은 코드 재사용을 더 중시한다는 결정을 했다고 볼 수 있는 거죠.
게다가 요즘 CPU에서 스택에 4바이트를 넣느냐 8바이트를 넣느냐는 무한 재귀호출을 돌리지 않는 이상 사실상 성능에 아무런~ 차이가 없습니다. 그런 차이는 그냥 무시하시는 게 답입니다.
1. 일단 가변 인수 사용 방법이 틀렸습니다.
1. 일단 가변 인수 사용 방법이 틀렸습니다.
정석적으로 사용하려면 아래와 같이 사용해야 됩니다.
C언어에서 포인터 산술을 지원한다고, 제멋대로 막 쓰면 안 되는 겁니다.
가변 인수를 스택에 어떤 레이아웃으로 올릴지는 컴파일러 재량이고, 함부로 가정해서는 안 되지요.
저는 솔직히 *printf/*scanf류 함수 인터페이스를 구현해야 할 때를 제외하고는 C언어의 가변 인수 기능을 사용하는 것 자체를 별로 권장하지 않습니다만,
만약 써야만 한다면 위와 같이 언어 차원에서 제공하는 방식을 써야 합니다.
2. who cares?
C언어에서는 "컴파일러가 반드시 보장해 줘야 하는 것"이 있는 반면, "컴파일러가 재량껏 할 수 있는 것"도 있습니다.
앞서 간단히 말씀드렸듯이, 가변 인수를 전달하기 위한 스택 메모리 레이아웃은 명백히 후자입니다.
컴파일러가 보장해 주는 건, va_list를 적절히 조작하면 넘겨 받은 인수를 모두 읽을 수 있다는 것뿐이죠.
"난 4바이트짜리 int를 보내고 싶은데 왜 8바이트 정렬을 해 놨냐"고 따져봤자 "컴파일러 마음이다"라는 답밖에 들을 수가 없어요.
게다가 낭비되는 자원이라고 해 봤자 별 거 없을 겁니다. 가변 인수로 매개변수를 백 개쯤 보낼 것도 아니고, 설령 그렇게 한다 해도 400byte 정도밖에 더 되나요.
3. 정 신경이 쓰인다면...
int 배열을 쓰세요.
제 생각엔, 주어진 use case에서는 이렇게 쓰는 게 더 깔끔해 보입니다.
구체적으로 메모리가 어떻게 쓰일지는 (또다시) 여전히 컴파일러 재량이긴 합니다만.
댓글 달기