본 내용은 http://blog.naver.com/daeel74?Redirect=Logamp;logNo=40006990801 에서 발췌하였음을 밝힙니다.br /br /br /br /br /table id=printPost1 class=post-body cellpadding=0 cellspacing=0tbodytrtd class=bcl nowrap=nowrapbr //tdtd class=bcc !-- 제목 -- table class=post-toptbodytrtd valign=bottom div class=htitle span class=pcol1 itemSubjectBoldfont[C언어의 진화] ② C99의 신기술들/span span class=cate pcol2img src=http://blogimgs.naver.com/imgs/nblog/spc.gif class=pcol2b fil3 alt= height=11 width=1a href=javascript:PostList('daeel74','11'); class=pcol2Computer Science/a img src=http://blogimgs.naver.com/imgs/nblog/spc.gif alt= height=1 width=105/span /div p class=date fil5 pcol22004/10/20 20:45/p p class=urla href=http://blog.naver.com/daeel74/40006990801 target=_top class=fil5 pcol2http://blog.naver.com/daeel74/40006990801/a/p /td/tr/tbody/table div class=post-view pcol2 !-- 포스팅 -- a class=con_link href=http://www.zdnet.co.kr/techupdate/lecture/etc/0,39024989,39130477,00.htm target=_blankufont color=#0000ff지난 글/font/u/a에 이어 소개할 기술들은 이전의 C 언어가 가진 문제들과 그 해결책이 C 언어 표준화의 원칙을 만족하여 C99에 새로 입성한 것들이다. 자신이 C 프로그래밍을 하면서 느꼈던 실질적인 불편함이나 이곳에서 설명하고 있는 문제를 경험에 비추어 떠올리면서 항목 하나하나를 살펴본다면 기술적인 내용이 길게 진행되더라도 크게 지루하지는 않을 것이다. br /br /b수식 없는 return 문의 제거[Lang][Open]/b br /void 형은 함수의 반환 값이나 매개변수가 없음을 명시적으로 표시하기 위해 사용된다. 우리에게 낯설지 않은 이 void 형은 사실 C 언어의 첫 번째 표준인 C90에서 도입된 것이다. 그보다 과거에는 앞서 소개했던 암시적인 int 형(implicit int)이 그 역할을 대신했다. br / div style=margin-left: 15px;br /int foo(int param) nbsp; nbsp; nbsp; nbsp;bar(int param) br /{ nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp;{ br /nbsp; nbsp;/* ... */ nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp;/* ... */ br /nbsp; nbsp;return result; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; return; br /} nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; } br //divbr /암 시적인 int 형에 의해 함수 bar()의 반환형은 foo()와 동일한 int 형이고 단지 그 반환값이 정의되지 않은 값일 뿐이지만, 프로그래머들은 관례적으로 반환형에 암시적인 int 형을 사용한 함수를(마치 지금의 void bar(int param);인 것처럼) 반환값이 없는 함수로 사용하며 함수 안에서 수식이 따라오지 않는 return 문을 사용해왔다. 이러한 관례는 암시적인 int 형이 유지되었던 C95까지도 지원됐으나, C99에서 갑작스럽게 암시적인 int 형을 제거하면서 반환형에 명시적으로 void 형을 쓰지 않은 함수에서 수식이 없는 return 문을 쓰지 못하도록 금지했다. 이는 결과적으로 바람직한 변화라고 할 수 있으나 기존의 C90이나 C95 관점에서 분명히 올바르던 코드를 배려하지 않은 다소 다급한 변화이기도 하다. br /br /b행동이 정의된 음의 정수 나눗셈 결과[Lang][Open]/b br /친 숙한 사실이겠지만 C 언어의 나눗셈 연산자는 우리가 알고 있는 수학과 다르다. 즉 피연산자가 모두 정수형인 경우 나눠떨어지지 않는 경우에도 결과는 정수로 나온다. 또 하나 프로그래머들이 쉽게 잊고 있는 사실은 정수 나눗셈 연산이 이루어질 때 두 피연산자 중 하나라도 음수라면 그 결과가 컴파일러에 따라 달라질 수 있다는 사실이다. 두 피연산자 모두가 양수이며 나머지가 발생하는 경우 항상 몫의 소수점 이하를 버려서 정수 결과를 얻지만, 둘 중 하나라도 음수이면(둘다 음수인 경우도 포함) 소수점 이하를 버릴지, ±∞ 쪽으로 반올림이 이루어질지 표준이 정의하지 않는다. br / div style=margin-left: 15px;br /int q = 7 / -3; nbsp; /* -2 or -3 */ br /int r = 7 % -3; nbsp; /* 1 or -2 */ br //* 단, r == 7 - (q * -3) 를 만족 */ br //divbr /최대한의 이식성을 걱정하는 프로그램은 다음과 같은 방법을 통해 환경에 무관하게 나눗셈과 나머지 연산자의 결과를 목적에 맞도록 조정해왔다(예에서 r, q, a, b는 모두 정수형이다). br /!-- 큰 이미지 하나 중간에 놓을때 사용하는 소스입니다. --br / center table width=420 tbody tr td align=middleimg src=http://www.zdnet.co.kr/images/stories/etc/2004/10/1019_C99/untitled-1.jpg/td/tr tr td class=bk align=middlebr //td/tr/tbody/table/centerbr /하 지만 음의 정수를 피연산자로 갖는 나눗셈 결과를 ∞ 쪽으로 반올림하는 환경이 C90이 제정될 당시에도 소수였던 만큼 C99가 제정될 당시에는 한 표의 반대 없이 음수를 포함한 정수 나눗셈의 결과를 항상 소수점 이하 버림으로 정의할 수 있었다. 참고로 표준이 선택한 방식은 포트란을 따르는 것이며, 표준이 금지한 방식은 과거 파스칼에서 만날 수 있던 방식이다. br /br /b지정된 초기치[Lang][Open]/b br /C 언어가 제공하고 있는 배열이나 구조체 혹은 공용체의 초기화 규칙은 지나치게 엄격한 면이 없지 않았다. 우선 공용체의 경우 항상 첫 번째로 선언된 멤버만을 초기화할 수 있었다. 따라서 초기화하려는 대상이 바뀌면 공용체의 멤버 선언 순서를 바꿔야만 했다. br / div style=margin-left: 15px;br /union { int a; double b; } foo = { 12 }; br //* 멤버 int a를 위한 초기치 */ br //divbr /또한 배열이나 구조체를 초기화할 때 중간에 존재하는 멤버 일부만을 초기화하는 경우 그 이전의 모든 요소나 멤버에 초기치를 제공해야만 했다. br / div style=margin-left: 15px;br /int a[200] = { /* 100개의 적당한 초기치 */, 7903, }; br //* a[100]을 7903으로 초기화 */ br //divbr /이러한 불편을 해소하고자 C99에는 특정 멤버나 요소를 직접 지정해 초기치를 제공할 수 있는 방법을 제공한다. br / div style=margin-left: 15px;br /union { int a; double b; } foo = { .b = 3.14159 }; br /int a[200] = { [100] = 7903 }; br //divbr /이 렇게 지정된 멤버에 대해 초기치를 제공하는 방식은 다음 호에 소개할 복합 상수(compound literal)와 함께 프로그램에 강력한 유연성을 제공할 수 있다. 물론 여기서는 간단히 단순 배열과 구조체에 대한 예를 보았으나 배열을 멤버로 포함하는 구조체 등의 경우에도 이 방법은 재귀적으로 적용된다. br /br /b집합체나 공용체 초기치의 제한 완화[Lang][Open]/b br /함 수 내부에서 선언되어 자동 기억 수명(auto storage duration)을 갖는 스칼라형(scalar type)의 변수는 초기치가 상수 수식이 아니어도 상관없다. 하지만 집합체(aggregate, 배열과 구조체를 묶어 부르는 용어)나 공용체의 경우에는 기억 수명이 정적(static)이 아닌 경우에도 언어의 복잡성을 제거한다는 이유로 초기치를 상수 수식으로 제한해왔다. C99는 자동 기억 수명에 한해서 집합체나 공용체의 초기치가 상수 수식이 아닐 수 있도록 허용하고 있다. br / div style=margin-left: 15px;br /int base = 12; br /int static_duration[10] = br /nbsp; nbsp; { base+1, base+1, base+2, base+3, }; nbsp; nbsp;/* wrong in C90/C99 */ br /br /void foo(void) br /{ br /nbsp; nbsp; int local_base = 79; br /nbsp; nbsp; int auto_duration[10] = br /nbsp; nbsp; nbsp; { base+1, base+1, base+2, base+3, }; nbsp; nbsp;/* okay in C99 */ br /nbsp; nbsp; /* ... */ br //divbr /자동 기억 수명의 집합체형 초기치를 상수 수식으로 제한하지 말자는 요구는 사실 C90 시절부터 있었기에 굳이 C99를 지원하지 않는 환경에서도 확장을 통해 이 기술을 사용할 수 있다. br /br /bC++ 스타일의 주석[Lang][Open][C++]/b br /C90 은 C++ 스타일의 주석을 지원하지 않았다. 하지만 C++가 널리 인기를 얻으면서 C에서도 C++ 형태의 주석을 사용하는 사람이 늘게 되었고 대부분의 C/C++ 컴파일러는 특별히 C90이나 C95를 엄격히 지키도록 옵션을 주지 않는 이상 C 프로그램에서도 C++ 주석을 사용할 수 있도록 배려해왔다. C99는 이러한 관례를 받아들이고, 동시에 C와 C++ 사이의 차이를 최소화하기 위해서 본격적으로 C에 C++ 주석을 도입하게 된다. 실질적인 프로그램에 영향을 주는 경우가 드물기는 해도 이 작은 변화는 이전 호에서 언급했던 ‘조용한 변화’에 해당한다. 예를 들어 다음 프로그램은 C90/C95와 C99(혹은 C++)에서 다른 결과를 보인다. br /br / center table width=420 tbody tr td align=middleimg src=http://www.zdnet.co.kr/images/stories/etc/2004/10/1019_C99/untitled-2.jpg/td/tr tr td class=bk align=middlebr //td/tr/tbody/table/centerbr /많 은 사람들이 C/C++ 주석의 구분 없이 C99 발표 이전부터 C 프로그램에서 C++ 주석을 사용해 왔지만 사실상 C++ 주석은 C99를 지원하는 환경에서만 적법하게 C 프로그램에 사용할 수 있다는 사실을 기억할 필요가 있다. 예를 들어 표준(C90/C95)을 준수하며 최소한의 확장을 지원하는 개발 환경에서는 여전히 C 언어 고유의 주석만을 허락하며 프로그래머의 잘못된 습관으로 C++ 주석을 다수 사용한 C 프로그램을 해당 환경으로 옮기는 작업은 여간 고역이 아닐 수 없다. br /br /b암시적인 함수 선언 제거[Lang][Open]/b br /현 대 프로그래밍 언어의 원칙 중 하나는 프로그램에서 사용되는 모든 명칭은 적절하게 선언되어야 한다는 것이다(그래야 적절한 데이터형 검사를 통해 안정성을 확보하기 용이해진다). 하지만 C 언어는 그 시작을 데이터형을 갖지 않는 BCPL, B 언어에 두고 있기에 함수 선언과 관련된 부분에서도 이전에 다루었던 암시적인 int 형과 유사한 특징을 갖는다. br /br / center table width=420 tbody tr td align=middleimg src=http://www.zdnet.co.kr/images/stories/etc/2004/10/1019_C99/untitled-3.jpg/td/tr tr td class=bk align=middlebr //td/tr/tbody/table/centerbr /이 예에서 볼 수 있듯이 만약 어떤 함수 foo()가 선언이 제공되지 않은 상태에서 호출되면 그 함수가 호출되는 가장 안쪽 통용범위(scope)에 외부 연결(external linkage)을 갖고 정수형을 반환하며 매개변수에 대한 정보가 알려지지 않은 함수 선언(암시적인 함수 선언)이 존재하는 것처럼 동작한다. br /br /또한 만약 실제 함수의 정의 형태가 암시적인 함수 선언과 호환된다면 프로그램 자체는 기술적으로 올바른 구조가 된다. 하지만 이런 구조는 암시적인 함수 선언이 허용되던 시절에도 그리 바람직하지 않은 것으로 인식되어 왔기에 C99에서는 모든 함수가 빠짐없이 호출 전에 적절히 선언되도록 요구하고 있다. 이번에도 표준은 암시적인 선언을 구식 기술로 규정하는 기간 없이 갑작스럽게 제거했으나 다수의 컴파일러는 적절한 경고 메시지를 보여주며 계속 암시적인 함수 선언을 지원함으로써 점차 금지해나갈 것으로 보인다. br /br /b선언과 문장 섞어 쓰기[Lang][Open][C++]/b br /C 는 C++와 달리 모든 블럭(block, compound statement) 내에서 선언을 문장보다 앞에 두어야 한다는 다소 엄격한 규칙을 가지고 있었다. 이러한 규칙이 선언을 한 곳에 집중시킨다는 장점을 갖지만 동시에 함수의 길이가 길어지는 경우 선언을 확인하기 위해 매번 함수의 시작 부분을 찾아봐야 한다는 단점을 갖는다. 물론 한 함수가 담당하는 일이 논리적으로 구분된 몇 개의 작업으로 나뉘는 경우 다음과 같이 중첩된 블록을 사용해 프로그램의 가독성을 높이는 것도 가능하다. br / div style=margin-left: 15px;br /double foo(void) br /{ br /nbsp; nbsp; double result, sum; br /br /nbsp; nbsp; {nbsp; nbsp; /* 첫 번째 논리적 단위 작업 */ br /nbsp; nbsp; nbsp; nbsp; int first_result; br /nbsp; nbsp; /* ... */ br /nbsp; nbsp; } br /nbsp; nbsp; {nbsp; nbsp; /* 두 번째 논리적 단위 작업 */ br /nbsp; nbsp; nbsp; nbsp; int second_result; br /nbsp; nbsp; nbsp; nbsp; /* ... */ br /nbsp; nbsp; } br /nbsp; nbsp; /* ... */ br //divbr /그렇지만 C++를 비롯한 요즘의 언어들이 그러하듯이 문장과 선언을 섞어서 쓸 수 있도록 허락하는 것이 실보다는 득이 더 많다는 판단 아래 C++와 마찬가지로 문장과 선언을 섞어 쓸 수 있도록 허용하게 됐다. br / div style=margin-left: 15px;br /double foo(void) br /{ br /nbsp; nbsp; double result, sum; br /br /nbsp; nbsp; /* 첫 번째 논리적 단위 작업 */ br /nbsp; nbsp; int first_result; br /nbsp; nbsp; /* ... */ br /br /nbsp; nbsp; /* 두 번째 논리적 단위 작업 */ br /nbsp; nbsp; int second_result; br /nbsp; nbsp; /* ... */ br //divbr /물 론 이처럼 문장과 선언을 섞어 사용할 때는 그 도입 취지를 분명히 이해해 프로그램의 가독성을 증진시키는 방향으로 사용해야 한다. 이 기술의 경우 양날의 칼과 같기에 잘못 사용할 경우 프로그램을 이해하기 어렵게 만드는 부작용을 낳을 수도 있다. br /br /b가변 인자 매크로[Lang][Open]/b br /C90/C95는 printf()처럼 가변 인자를 받는 함수를 표준 라이브러리인 stdarg.h를 통해 지원하지만 가변 인자를 받는 매크로 함수(function-like macro)는 지원하지 않았다. 매크로에 가변 인자를 허용하는 경우 디버깅에 빈번하게 사용되는 매크로 함수 등을 손쉽게 작성할 수 있기에 다수의 컴파일러는 확장을 통해 나름대로 그 방법을 제공해 왔다. 하지만 이식성을 고려하는 프로그램은 반드시 가변 인자 매크로가 필요한 경우 다음과 같은 편법을 통해 원하는 바를 이루기도 했다. br / /stdarg.hdiv style=margin-left: 15px;br /#define debug(args) printf args nbsp; nbsp; nbsp;#define comma , br /debug((%d, %d\n, i, j)); nbsp; nbsp; nbsp; nbsp; nbsp; #define debug(s, args) printf(s, args) br /nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp; nbsp;debug(%d, %d\n, i comma j); br //divbr /가변 인자 매크로의 필요성은 C90 시절부터 제기되어 왔으나 C99에 와서야 그 요구가 받아들여져 이제 컴파일러의 확장에 의존할 필요 없이 가변 인자 매크로를 구현할 수 있는 통일된 방법이 생겼다. br / div style=margin-left: 15px;br /#define debug(s, ...) printf(s, __VA_ARGS__) br //divbr /이 방법은 stdarg.h에 서와 유사한 방식을 사용한다는 장점을 갖지만 기존의 컴파일러 확장에서 찾아보기 어려운 형태이기에 C99를 전혀 지원하지 않는 컴파일러에서는 사용이 불가능하다는 단점을 갖는다. 만약 사용 중인 컴파일러가 C99에 부합하는 방법과 기존의 확장을 모두 제공한다면 과감히 표준이 제공하는 방법을 선택하는 것이 바람직하다. br /br /b빈 매크로 인자[Lang][Open]/b br /가 변 인자 매크로와 더불어 매크로 함수에서 유용하게 사용되는 것 중 하나가 빈 매크로 인자이다(이 경우 해당 매크로에서 기본값을 제공하는 개념이 아니라 일종의 빈 토큰이 제공되는 방식이다). 매크로 함수에서 인자 개수와 매개변수가 정확하게 일치해야 한다는 규칙으로 빈 매크로 인자를 제공하는 것 역시 그동안 비표준인 컴파일러 확장을 통해 사용해왔다. C99에서는 가변 인자 매크로를 도입하면서 동시에 빈 매크로 인자도 허용한다. br / /stdarg.hdiv style=margin-left: 15px;br /#define decl_ptr(prefeix, num) \ br /nbsp; nbsp; char *prefix ## num = #num br /decl_ptr(element, 13); br /nbsp; nbsp; /* char *element13 = 13; */ br /decl_ptr(element, ); br /nbsp; nbsp; /* char *element = ; */ br //divbr /이 예는 빈 매크로 인자를 사용하는 모습을 보여주는 것으로 두 번째 decl_ptr() 호출은 빈 매크로 인자를 지원하지 않는 C90/C95에서는 잘못된 것이다(물론 다수의 C90/C95 컴파일러가 확장을 통해 이를 지원하고는 있다). br /br /bprintf()의 %lf 지원[Lib][Open]/b br /많은 C 프로그래머들이 혼동하는 것 중 하나가 double 형을 printf()를 통해 인쇄할 때 다음과 같은 방식을 사용한다는 것이다. br / div style=margin-left: 15px;br /printf(%lf\n, 3.14159); nbsp; nbsp;/* wrong in C90 */ br //divbr /이 는 기본적으로 %f가 float 형에 대응하기 때문에 이보다 큰 double 형에는 %lf를 써줘야 한다는 오해나, scanf()에서는 %lf가 double 형에 대응하기 때문에 printf() 역시 동일할 것이라는 착각에 기인한다. 중요한 사실은 printf()처럼 가변 인자를 받는 함수의 가변 인자들에는 기본 인자 진급(default argument promotion)이 적용되기 때문에 float 형이 항상 double 형으로 변환되어 전달된다. 즉 printf() 함수의 입장에서는 float 형을 받을 수 없고 항상 double 형만 오기에 float 형과 double 형을 구분할 필요가 없는 셈이다. 따라서 다음 예에서 보는 것처럼 float 형과 double 형은 동일하게 %f를 통해 출력할 수 있다. br / div style=margin-left: 15px;br /printf(%f, %f\n, 3.14159f, 3.14159); br //divbr /프로그래머의 오해가 논리적으로 지극히 자연스럽고, 또 scanf()와 printf() 사이의 대칭성을 맞추기 위한 노력으로 C99에서는 %lf를 새로 도입하고 그 의미를 %f와 동일한 것으로 정의해주고 있다. br /br /bsnprintf() 함수군의 도입[Lib][Open]/b br /sprintf ()는 fprintf()와 유사하지만 스트림(stream)이 아닌 문자열로 그 결과를 출력하는 함수이다. 따라서 결과를 저장하기 위한 버퍼를 제공받게 되고 버퍼의 길이를 알 수 없기에 출력 결과가 버퍼의 크기보다 클 경우 곧바로 버퍼 오버런(buffer overrun)을 일으키게 된다. 이러한 이유로 sprintf()는 오래 전부터 보안에 취약한 함수로 인식되어 왔으며 C90 제정 당시 더욱 안전하게 버퍼의 길이를 제공하고 출력이 그 길이를 넘지 않도록 해주는 snprintf() 함수를 추가하자는 제안이 있었으나 2/3의 득표를 얻지 못해 제외된 바 있다. C99에서는 그 제안이 받아들여져 snprintf()가 표준 함수로 제공된다(이전에는 다수의 컴파일러가 확장을 통해 이를 제공해왔다). br /br /b중복 가능한 형 한정어[Lang][Lib][Open]/b br /‘idempotent’ 란 여러번 사용되어도 한번 사용된 것과 동일한 결과를 갖는 특성을 말한다. C 언어에서 const나 volatile 같은 형 한정어(type qualifier)는 직접적이든 typedef를 통해서든 같은 것을 중복 사용할 수 없었다. br / div style=margin-left: 15px;br /const const int i; nbsp; nbsp;/* wrong in C90 */ br /int * volatile volatile i; nbsp; nbsp;/* wrong in C90 */ br //divbr /하지만 C99에서는 이를 허락한다. 그 이유 중 하나는 바로 C 언어에서 비동기 시그널(asynchronous signal)에서도 항상 원자적으로 접근할 수 있음이 보장되는 데이터형인 sig_atomic_t(signal.h에 선언되어 있다)와 관련되어 있다. sig_atomic_t는 환경마다 다른 정수형으로 정의되는 typedef 명으로 보통 시그널 핸들러(asynchronous signal handler) 안에서 시그널이 발생했음을 알리는 플래그(flag) 역할을 한다. br /br /문 제는 표준이 시그널 핸들러 안에서 그와 같은 용도로 사용할 수 있는 데이터형을 sig_atomic_t가 아닌 volatile sig_atomic_t로 규정하고 있다는 사실이다. 그럼에도 불구하고 많은 프로그래머들은 습관적으로 sig_atomic_t만으로 시그널 핸들러용 플래그를 선언해왔고 이를 위해 다수의 컴파일러는 sig_atomic_t 형에 이미 volatile을 포함시켜 왔다. 이 경우 표준을 올바르게 지키고 volatile sig_atomic_t 형을 사용한 프로그램들은 sig_atomic_t에 내재되어 있는 volatile 때문에 동일한 형 한정어를 중복 사용하게 된다. br /br /따라서 C 표준은 형 한정어 중복을 허용함으로써 그와 같은 잘못된 프로그램과 컴파일러를 포용한 것이다. 한 가지 기억해야 할 사실은 사용하는 라이브러리의 signal.h에 sig_atomic_t가 voaltile을 포함하든 그렇지 않든 표준을 따르는 프로그램은 시그널 핸들러용 플래그를 선언할 때는 여전히 volatile sig_atomic_t를 사용해야 한다는 것이다. br /br /bva_copy() 매크로[Lib][Open]/b br /C90에서는 가변 인자를 제어하기 위해 사용되는 va_list 형(stdarg.h에 선언되어 있음)의 변수를 안전하게 복사할 수 있는 방법을 제공하지 않았다. 즉 va_start()-va_end() 쌍을 두 번 사용하지 않고 동시에 가변 인자를 두 번 훑을 수 있는 이식성 있는 방법이 존재하지 않았다. br / /stdarg.h/signal.h/signal.hdiv style=margin-left: 15px;br /int foo(int n, ...) br /{ br /nbsp; nbsp; int i, sum; br /nbsp; nbsp; va_list ap, aq; br /br /nbsp; nbsp; va_start(ap, n); br /nbsp; nbsp; while ((i = va_arg(ap, int)) gt;= 0) br /nbsp; nbsp; nbsp; nbsp; sum += i; br /nbsp; nbsp; aq = ap; nbsp; nbsp;/* 복사 시도: 안 될 수도 있음 */ br /nbsp; nbsp; for (i = 0; i lt; n; i++) br /nbsp; nbsp; nbsp; nbsp; sum += va_arg(ap, int); br /nbsp; nbsp; for (i = 0; i lt; n; i++) br /nbsp; nbsp; nbsp; nbsp; sum -= bar(va_arg(ap, int)); br /nbsp; nbsp; va_end(ap); br /br /nbsp; nbsp; return sum; br /} br //divbr /이 예에서는 aq에 ap를 대입함으로써 가변 인자 리스트를 동시에 두번 스캔할 수 있는 정보가 완전히 복사됐다고 가정하고 있다. 만약 컴파일러가 다음과 같은 방법으로 가변 인자 리스트를 관리한다면 이 프로그램은 작동하지 않는다(표준은 가변 인자를 관리하는 구체적인 방법을 각 컴파일러에게 맡기고 있다). br /br / div style=margin-left: 15px;font color=#2e3192◆ va_list/font : 가변 인자 정보를 저장할 수 있는 특정 자료 구조를 가리키는 포인터형 br /font color=#2e3192◆ va_start()/font : 그 자료 구조의 메모리를 할당해 ap가 그 메모리를 가리키도록 한다. br /font color=#2e3192◆ va_end()/font : ap가 가리키는 메모리를 해제한다. br /font color=#2e3192◆ va_arg()/font : 가변 인자를 하나 가져오며 ap가 가리키는 자료 구조의 특정 값을 변화시킨다./divbr /이 경우 aq는 ap와 같은 자료 구조를 가리키게 되고, 이미 ap와 함께 va_arg()가 수행되기에 ap가 가리키는 자료 구조의 값이 변화할 때 aq가 가리키는 자료 구조의 값 역시 변하게 된다. C99에서는 가변 인자 리스트에 대한 정보를 항상 적법하게 복사할 수 있는 방법을 제공하기 위해 va_copy() 매크로를 추가로 제공하게 됐다. 따라서 앞에서 aq = ap;라는 수식을 va_copy(aq, ap);로 대체하고 마지막에 va_end(aq);를 추가하면 해당 예제는 올바른 C99 프로그램이 된다. br /br /b더 엄격해진 구조체형 호환 규칙[Lang][Open]/b br /두 개의 분리된 소스 파일에서 호환되는 구조체형을 기술하고자 할 때 보통은 구조체 태그(tag)를 동일하게 맞춰주게 된다. 이는 많은 C 언어 책이 오랫동안 강조해온 사실이기에 다수의 프로그래머가 인지하고 있지만 사실 이것이 C99 이전까지는 C 표준이 강요하는 규칙이 아니라는 사실을 알게 된다면 조금 허탈할지도 모르겠다. 즉 다음의 두 소스 파일에 있는 struct foo와 struct bar는 (C90/C95에서는) 호환되는 데이터형이고 두 소스 파일에서 변수명 obj는 동일한 대상체(object)를 의미한다. br / center table width=420 tbody tr td align=middleimg src=http://www.zdnet.co.kr/images/stories/etc/2004/10/1019_C99/untitled-4.jpg/td/tr tr td class=bk align=middlebr //td/tr/tbody/table/centerbr /하지만 엄연히 호환되는 두 구조체형은 비록 분리된 소스 파일에서 선언될 때도 같은 태그를 갖는 것이 바람직하기에 C99에서는 태그까지 동일해야 한다는 규칙을 추가하게 됐다. br /br /bC90/C95와 C99 차이/b br /중 간 중간 다소 난이도 있는 이야기도 있었지만 가능한한 간략하고 효율적으로 C90/C95와 C99의 차이를 전달할 수 있도록 노력했다. 다음 호에서도 유사한 흐름으로 나머지 기술 중 주요한 것들을 살펴보고 너무 방대한 설명이 필요하거나 지나치게 사소한 것들은 하나로 묶어 소개하도록 하겠다. 이번 원고에 대한 어떠한 지적이나 질문, 의견도 환영이다. 필자의 메일이나 홈페이지 게시판을 통해 알려주면 자세한 답변을 드릴 것을 약속한다. @ 전웅 (ICU 석사과정) br /br / table align=center border=0 cellpadding=0 cellspacing=0 width=400 tbody tr td class=bk table border=0 cellpadding=0 cellspacing=0 width=100% tbody tr td width=7img src=http://images.zdnet.co.kr/img/edit_table/table8_1.gif height=24 width=7/td td class=bk background=http://images.zdnet.co.kr/img/edit_table/table8_1_bg.gif valign=baseline width=300C99 컴파일러/td td width=34img src=http://images.zdnet.co.kr/img/edit_table/table8_2.gif height=24 width=34/td td background=http://images.zdnet.co.kr/img/edit_table/table8_3_bg.gifnbsp; /td td width=5img src=http://images.zdnet.co.kr/img/edit_table/table8_7.gif height=24 width=5/td/tr/tbody/table/td/tr tr td background=http://images.zdnet.co.kr/img/edit_table/table8_bg.gif table border=0 cellpadding=0 cellspacing=0 width=100% tbody tr td bgcolor=#000000 width=1br //td td table border=0 cellpadding=0 cellspacing=10 width=100% tbody tr td class=bk table border=0 cellpadding=0 cellspacing=0 width=100% tbody tr td table border=0 cellpadding=0 cellspacing=0 width=100% tbody tr td class=bk여기서 소개하는 C99 기술들을 과연 어떤 환경에서 사용할 수 있는지 궁금한 독자들이 있을 것이다. 현재 상용 컴파일러 다수는 C99 기술을 완벽하게 지원하고 있으나 오픈소스 환경 등에서 사용되는 공개 컴파일러는 점점 더 나아지고 있기는 하지만 C99를 부분적으로만 지원하고 있는 상태이다. 구체적인 컴파일러를 몇 가지 언급해 보면 다음과 같다. br /br /◆ Comeau C/C++ compiler + Dinkumware library(http://www.comeaucomputing.com, http://www.dinkumware.com) br /Comeau 사에서는 다양한 환경에서 C99를 완벽하게 지원하는 컴파일러를, Dinkumware사에서는 유사하게 C99를 완벽하게 지원하는 표준 라이브러리를 상대적으로 저렴한 가격에 제공하고 있다. 이 둘을 합해 사용하면 온전한 C99 환경을 얻게 된다. br /◆ Intel C compiler(http://www.intel.com/software/products/compilers) br /인텔에서 리눅스와 MS 윈도우 환경을 위해 판매하고 있는 icc 역시 C99를 지원하고 있다. br /◆ MIPSpro ANSI C Compiler(http://www.sgi.com/software/irix/tools/c.html) br /SGI에서 배포하는 IRIX용 컴파일러도 C99를 지원하고 있다. br /◆ GNU gcc(http://gcc.gnu.org) br /C/C++ 이외에도 다양한 언어를 지원하는 gcc 역시 C99를 부분적으로 지원하고 있다. gcc가 지원하고 있는 C99 기술에 대한 내용은 http://gcc.gnu.org/c99status.html에서 확인할 수 있다(다른 컴파일러도 마찬가지지만). gcc에서 C99를 부분적으로라도 지원하도록 실행하기 위해서는 -std=c99 같은 별도의 옵션이 필요하다. br /◆ lcc-win32(http://www.cs.virginia.edu/~lcc-win32) br /Christopher Fraser와 David Hanson의 lcc에 기반을 둔 MS 윈도우용 무료 C 컴파일러인 lcc-win32 역시 다소 더디지만 C99를 꾸준히 지원해가고 있다./td/tr/tbody/table/td/tr/tbody/table/td/tr/tbody/table/td/tr/tbody/table/td/tr/tbody/table/div/td/tr/tbody/tablebr /
크리에이티브 커먼즈 라이센스
Creative Commons License
2007/06/08 14:17 2007/06/08 14:17
TAG ,
받은 트랙백이 없고, 댓글 span class="cnt"하나/span가 달렸습니다.

댓글+트랙백 RSS :: http://blog.minzkn.com/rss/response/194

댓글+트랙백 ATOM :: http://blog.minzkn.com/atom/response/194

트랙백 주소 :: http://blog.minzkn.com/trackback/194

트랙백 RSS :: http://blog.minzkn.com/rss/trackback/194

트랙백 ATOM :: http://blog.minzkn.com/atom/trackback/194

댓글을 달아 주세요

댓글 RSS 주소 : http://blog.minzkn.com/rss/comment/194
댓글 ATOM 주소 : http://blog.minzkn.com/atom/comment/194
  1. 김민수 2007/06/13 22:29  댓글주소  수정/삭제  댓글쓰기

    http://www.sgi.com/software/irix/tools/c.html

    링크는 페이지 찾을수 없음입니다. :)

    인텔 컴파일러가 역시 자기네 인텔CPU x86에선 최고의 성능 아닌가요? gcc와 비교해선 확실히 최적화가 틀려지는건 봤는데,

    밉스프로는 안써봐서 모르겠네요.

    밉스는 펜티엄 나오기전 옛날엔 부동소수점연산이 risc라 역시 우위였지만

    지금은 정수던 부동소수던간에 모두 인텔 x86계열이 압도적으로 우위를 가지는거로 압니다. 당연하겠지만 너무 많은 발전때문이긴 한데..

    irix에서 밉스프로 컴파일러로 하면 달라질려나? 그건 아니겠죠? ㅋㅋㅋㅋ

    지금 생각해보면 밉스가 참 가격대 성능비로 보면 최고인거 같긴 한데... x86에 왜 밀렸을까 하는 의문이..