이식성 있는 프로그램의 작성 시 함수 파라미터의 사용을 피하는

unipro의 이미지

바이트 순서가 다른 프로세서들 간의 프로그램을 이식할 때에는
특히 함수에 파라이터를 전달할 때 문제가 발생할 수 있다.
함수 파라미터의 어드레스를 사용하지 않아야 한다.
예를 들어, 다음과 같다.

char z;
func(z);

func(char zz) {
	char *p, tmp;

	/* 밑에 분이 지적하신 오타를 수정했습니다. */
	p = &zz /* (1) 좋은 방법이 아니다 */
	tmp = zz;
	p = &tmp /* (2) 훨씬 더 안전하다 */

	/* ... */
}

(1)과 (2)는 어떤 차이가 있는 거지요?[url][/url]
stoneshim의 이미지

char z; 
func(z); 

func(char zz) { 
   char *p, tmp; 

   p = & /*(1) 좋은 방법이 아니다 */ 
   tmp = zz; 
   p = & /* (2) 훨씬 더 안전하다 */ 

   /* ... */ 
} 

혹시 원래 코드가 위와 같지 않고 아래와 같지 않나요?

char z; 
func(z); 

func(char zz) { 
   char *p, tmp; 

   p = &zz /*(1) 좋은 방법이 아니다 */ 
   tmp = zz; 
   p = &tmp /* (2) 훨씬 더 안전하다 */ 

   /* ... */ 
} 

인용하시려던 코드가 두번째 코드라면
이 의미는 파라미터 자체의 어드레스를 사용하는 것이 위험하다는 뜻입니다.

(1)의 경우가 파라미터 자체의 어드레스를 사용하는 것이구요.
(2)의 경우는 파라미터의 값을 stack 변수에 할당한 후 stack 변수의 어드레스를 사용하는 모습입니다.

우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자

unipro의 이미지

메모리에서 바이트를 다른 순서로 정렬하는 것에 대한 이식성하고
위에서 함수 파라미터의 어드레스를 사용하지 않는 것하고는
무슨 관계가 있는지 잘 이해가 가지 않습니다.

내 블로그: http://unipro.tistory.com

pynoos의 이미지

메모리 바이트 순서하고, 함수 파라미터 사용에 대한 것이라.....

크게 신경쓰이지 않는 문제같습니다.

pointer를 pointer 답게만 사용하면 되고,
강제로 long 등으로 바꾼뒤 무슨 연산을 하는 짓만 안하면,
그다지 문제가 되지 않습니다.

체스맨의 이미지

예제의 출처가 궁금하네요. 글쓴이가 무엇을 말하고 싶은 건지
모르겠습니다. '바이트 순서'가 바이트오더(byte order)를 의미한다면,
이기종간 바이트 오더가 중요한 문제이긴 합니다만,
지금 예제에서는 그 중요함에 대해 제대로 다루고 있는 것 같지 않아
보이구요, 특히 char 와 같이 단일 바이트인 경우는 바이트 오더에
구애받지 않습니다. 지금 예제는 char 타입인 경우를 다루고 있네요.

Orion Project : http://orionids.org

wizcat의 이미지

아무상관없음...

그문제의 포인가 뭔지는 모르겠지만..

(1)번과 (2)번은 똑같습니다..

local변수와 파라미터는 똑같이 stack영역에 생깁니다.

unipro의 이미지

Beginning Linux Programming - 2nd Edition, 정보문화사
부록 A 이식성 에서 바이트 순서 부분입니다.

저자가 잘못 알고 있을 것일까요?
저자가 자신의 생각을 표현하는데 문제가 있었던 것일까요?
번역에서 오류가 난 것일까요?
이것에 대해 아는 사람이 아직 나타나지 않을 것일까요?

내 블로그: http://unipro.tistory.com

unipro의 이미지

함수 파라메타는 함수로 넘어갈 때 확장될 수 있다네요. 예를 들어 char는 int로 확장되어서 넘어갈 수 있는 경우지요. 따라서 직접적으로 함수 파라이터의 어드레스를 사용할 경우 바이트 순서에 차이에 의해서 다른 결과를 얻을 수 있다고 하네요.

디스크의 데이터나 네트워크를 통한 데이터 전송의 경우는 예전부터 알고 있었는데, 함수 파라이터의 경우에도 잘못하면 이식성에 문제가 될 수 있더군요.

관심 갖지고 답변해준 동지님(?)들께 감사드립니다.

내 블로그: http://unipro.tistory.com

체스맨의 이미지

아, 그렇습니다. 저도 이해가 되네요.
말씀하신 책을 찾아봤는데, 그 책을 쓸 정도의 분이 이 정도를 간과할 것
같진 않았습니다. 사실 지금 예제 코드처럼 쓰는 경우는 거의 없지만,
문제는 일으킬 수 있겠네요.

대개 32비트 이상의 시스템에서는 기본 정수 크기 이하의 정수는
기본 정수 크기로 확장되어 넘어가죠. printf 에서도 이런 확장 규칙과
연관되게 되어 있죠.

좋은 예제네요. ^^

Orion Project : http://orionids.org

lsj0713의 이미지

흥미로운 주제라서 제가 han.comp.lang.c 뉴스그룹에 질문을 옮겼습니다.

http://groups.google.co.kr/groups?threadm=b6kcji%24dqg%241%40news1.kornet.net

Lee Huan Chul 님께서 답변을 달아주셨는데 아직 구글 뉴스그룹쪽으로 글이 전달되지 않은 것 같군요. 조만간 구글 쪽으로도 볼 수 있을 겁니다. :-)

간단하게 요약하면, 함수의 선언을 제대로 하지 않은 덕분에 생기는 문제 같군요. 선언을 다음과 같이 제대로 해주면 해결될 문제 같습니다.

void func(char zz);    /* 함수의 선언 */

void func(char zz)    /* 함수의 정의 */
{
    /* ... */
}

http://groups.google.co.kr/groups?selm=385e7ca.0304042126.104c13ce@posting.google.com

--------------------------------------------------------------------------------
Subject: Re: 함수의 파라미터의 포인터를 취하는 것에 대한 질문
From: Lee Huan Chul <lhc_forever at yahoo dot co dot kr>

"Lee, Sin-jae." <spammer@go.to.hell> wrote in message news:<b6kcji$dqg$1@news1.kornet.net>...

>> KLDP 프로그래밍 QnA 게시판에 다음과 같은 글이 올라왔더군요.
>> 
>> http://bbs.kldp.org/viewtopic.php?t=1364
>> --------------------------------------------------------------------------------
>> 
>> unipro - novice
>> 
>> 가입: 2002년 12월 25일 올린 글: 16
>> 올려짐: 2003년3월12일 13:18
>> 주제: 이식성 있는 프로그램의 작성 시 함수 파라미터의 사용을 피하는 	
>> 
>> 바이트 순서가 다른 프로세서들 간의 프로그램을 이식할 때에는
>> 특히 함수에 파라이터를 전달할 때 문제가 발생할 수 있다.
>> 함수 파라미터의 어드레스를 사용하지 않아야 한다.
>> 예를 들어, 다음과 같다.
>> 
>> 코드:
>> 
>> char z;
>> func(z);
>> 
>> func(char zz) {
>>    char *p, tmp;
>> 
>>    /* 밑에 분이 지적하신 오타를 수정했습니다. */
>>    p = &zz /* (1) 좋은 방법이 아니다 */
>>    tmp = zz;
>>    p = &tmp /* (2) 훨씬 더 안전하다 */
>> 
>>    /* ... */
>> }
>> 
>> (1)과 (2)는 어떤 차이가 있는 거지요?[url][/url]
>> 
>> unipro님이 2003년3월12일 13:52에 수정함, 총 1 번 수정됨
>> 
>> unipro
>> novice
>> 
>> 가입: 2002년 12월 25일
>> 올린 글: 16
>> 
>> 올려짐: 2003년4월4일 10:49    주제: 왜 함수 파라이터의 어드레스를 사용하
>> 지 않아야 하는지 대충 알 	
>> 함수 파라메타는 함수로 넘어갈 때 확장될 수 있다네요. 예를 들어 char는
>> int로 확장되어서 넘어갈 수 있는 경우지요. 따라서 직접적으로 함수 파라이
>> 터의 어드레스를 사용할 경우 바이트 순서에 차이에 의해서 다른 결과를 얻을
>> 수 있다고 하네요.
>> 
>> 디스크의 데이터나 네트워크를 통한 데이터 전송의 경우는 예전부터 알고 있
>> 었는데, 함수 파라이터의 경우에도 잘못하면 이식성에 문제가 될 수 있더군요.
>> 
>> 관심 갖지고 답변해준 동지님(?)들께 감사드립니다.
>> 
>> --------------------------------------------------------------------------------
>> 
>> 이 말이 정말입니까? 함수 파라미터의 주소값을 취할 때에는 특별히 주의해야
>> 하는 것인가요? 얼핏 보기에는 잘 이해가 안가는 부분입니다만...



일단 이런 근심을 하게되는 이유는 scope 내에 function prototype을
두지 않았기 때문인데 그런 기초적인 사항을 실수하고 이런 복잡한 내용을
이야기 하는게 조금 이상합니다만

x86 리눅스에서와 M$ 윈도에서 테스트를 해봤는데 문제는 발생하지 
않았습니다.



>> func(char zz) {
>>    char *p, tmp;
>> 
>>    /* 밑에 분이 지적하신 오타를 수정했습니다. */
>>    p = &zz /* (1) 좋은 방법이 아니다 */
>>    tmp = zz;
>>    p = &tmp /* (2) 훨씬 더 안전하다 */


이 부분을 보면 zz의 주소를 구하는 것은 좋은 방법이 아니라 하고 있는데
주소 값을 구하는 것 자체가 좋은 방법이고 아닌 방법이고 논할 바는 아니겠지요.
문제는 어떻게 쓰느냐인데 단순히 char 변수 가지고 주소를 1 증가 시킨다든지
하는 연산은 하지 않을 터이고 한다하면 다시 그 값을 참조 하는 일일진데
다시 참조한다 하여도 zz이 원래 가지고 있던 값이 나오겠지요.

즉 byte allignment가 문제시 된다면 zz의 포인터를 받아서 뭐하는게 문제가 아니라
zz값 자체에 문제가 있어야 합니다. argument type promotion rule에 따라 char는
int로 확장되어 어떤 endian 이냐에 따라 값이 딸라질 수 있다는 이야기를 하고픈
것인듯 싶은데 어쨌든 little endian 에서는 문제가 없군요.
--------------------------------------------------------------------------------
체스맨의 이미지

제 생각에는 함수 프로토타입을 지정하지 않은 것이 문제가 아니라,
원 질문자가 다시 적으신 그대로,

(1) 컴파일러 특성
(2) 컴파일러의 promotion rule
(3) 바이트 정렬

이 문제라고 봅니다.

프로토타입을 정해줘도, promotion이 행해지는 컴파일러가 있고,
제가 언급한 printf 와 같은 가변인자 함수인 경우는 명확한 type 을
프로토타입으로 정하지 않습니다. printf 를 직접 구현하는 경우는
시스템의 promotion rule 을 알아야 하죠.

프로토타입이 있어도 promotion 이 행해지는 예를 비쥬얼C++컴파일러
에 대해 들어보겠습니다.

void _stdcall f( char a, int b );

int
main
( void )
{
   f( 1, 2 );
   return 0;
}

이 소스를 컴파일 링크하면,
error LNK2001: unresolved external symbol _f@8

VC컴파일러는 _stdcall 인 경우, "함수이름@인자크기" 의 이름을
만들어냅니다. 인자크기는 바이트 수입니다. 8바이트는 char a가
4바이트로 promotion 됨을 의미합니다. f를 정의해서 인자 a와 b의
주소를 뺀 값은 써보면 역시 4 차이가 납니다. little endian인 경우는
당연히 문제 없지만,
1. big endian
2. promotion 을 행하는 컴파일러
라면 문제가 나타날 '수도' 있습니다.

물론 big endian 이라 하더라도, 컴파일러가 argument 의 pointer
를 취하는 경우를 알아서 판단하여, promotion 된 경우 적절한
pointer 를 지정하도록 처리해 준다면 문제가 발생하지 않을 수도
있겠죠. 하지만, 여전히 문제가 발생할 '가능성'은 있다고 봐야 합니다.
책의 저자도 가능성을 언급했을 뿐, 완전히 잘못됐다라고 단정짓지는
않았구요.

처음 질문에 제시한 예처럼 쓰는 경우는 거의 없지만, 함수 인자의
포인터를 다시 다른 함수로 넘기는 경우는 실수로 코딩할 수는
있을 것 같습니다.

Orion Project : http://orionids.org

체스맨의 이미지

글을 하나 더 올렸는데, 잘 못 생각한 부분이 있어 몇가지 테스트를
더 해봤습니다.

우선 위의 예에서 _stdcall 함수는 완전히 promotion 된 것으로 보긴 어렵고,
주소 정렬의 의미 ( structure byte alignment 와 같이 성능 향상
및 특정 시스템에서 bus error 를 피하기 위한. ) 로 봐야 하겠습니다.

전역 변수 char a 를 선언하여 함수 첫인자로 넣는 경우,
위의 첫 char 인자는 아래 어셈블리와 같이 4바이트로 푸쉬되고
상위 3바이트는 쓰레기 값으로 남습니다.
mov al, BYTE PTR _a
push eax

이 코드여야 promotion 이라고 볼 수 있겠죠.
movsx eax, BYTE PTR _a
push eax

어쨌든 위 두 경우 모두, 지금처럼 1바이트 정수가 4바이트 정수로 푸쉬된
경우라면 그 인자의 포인터를 얻는 데 있어서,

(1) 시스템 및 컴파일러 특성
(2) 컴파일러의 promotion rule
(3) 바이트 정렬

에 따라 문제가 나타날 '수도' 있습니다.

언급한 바와 같이, 컴파일러가 argument 의 pointer 를 취하는
경우를 알아서 판단하여, 주소 정렬된 경우 적절한 pointer 를
지정하도록 처리해 준다면 문제가 발생하지 않을 수도 있구요.

사족 : 제가 테스트한 시스템이 x86 계열 이므로, 시스템에 따라서는
void _stdcall f( char a, int b ) 함수의 인자 a 가 위에 제시한 어셈블리
코드와는 다르게 promotion 될 가능성도 있다고 볼 수 있습니다.
x86 계열에는 1바이트짜리 al레지스터가 존재하고, mov 가 movsx
보다 실행 클럭수가 적기 때문에 위와 같은 코드가 생성됐지만,
이것은 시스템 특성에 따라 달라질 수 있는 문제입니다.

Orion Project : http://orionids.org

전웅의 이미지

[hclc 에 올라온 질문에 답한 내용을 이곳에도 포스팅합니다]

"Lee Huan Chul" <lhc_forever@yahoo.co.kr> wrote in message news:385e7ca.0304042126.104c13ce@posting.google.com...
> "Lee, Sin-jae." <spammer@go.to.hell> wrote in message news:<b6kcji$dqg$1@news1.kornet.net>...
> > KLDP 프로그래밍 QnA 게시판에 다음과 같은 글이 올라왔더군요.
> >
> > http://bbs.kldp.org/viewtopic.php?t=1364
> > --------------------------------------------------------------------------------
> >
> > unipro - novice
> >
> > 가입: 2002년 12월 25일 올린 글: 16
> > 올려짐: 2003년3월12일 13:18
> > 주제: 이식성 있는 프로그램의 작성 시 함수 파라미터의 사용을 피하는
> >
> > 바이트 순서가 다른 프로세서들 간의 프로그램을 이식할 때에는
> > 특히 함수에 파라이터를 전달할 때 문제가 발생할 수 있다.
> > 함수 파라미터의 어드레스를 사용하지 않아야 한다.
> > 예를 들어, 다음과 같다.
> >
> > 코드:
> >
> > char z;
> > func(z);
> >
> > func(char zz) {
> > char *p, tmp;
> >
> > /* 밑에 분이 지적하신 오타를 수정했습니다. */
> > p = &zz /* (1) 좋은 방법이 아니다 */
> > tmp = zz;
> > p = &tmp /* (2) 훨씬 더 안전하다 */
> >
> > /* ... */
> > }
> >
> > (1)과 (2)는 어떤 차이가 있는 거지요?[url][/url]
> >
> > unipro님이 2003년3월12일 13:52에 수정함, 총 1 번 수정됨
> >
> > unipro
> > novice
> >
> > 가입: 2002년 12월 25일
> > 올린 글: 16
> >
> > 올려짐: 2003년4월4일 10:49 주제: 왜 함수 파라이터의 어드레스를 사용하
> > 지 않아야 하는지 대충 알
> > 함수 파라메타는 함수로 넘어갈 때 확장될 수 있다네요. 예를 들어 char는
> > int로 확장되어서 넘어갈 수 있는 경우지요. 따라서 직접적으로 함수 파라이
> > 터의 어드레스를 사용할 경우 바이트 순서에 차이에 의해서 다른 결과를 얻을
> > 수 있다고 하네요.
> >
> > 디스크의 데이터나 네트워크를 통한 데이터 전송의 경우는 예전부터 알고 있
> > 었는데, 함수 파라이터의 경우에도 잘못하면 이식성에 문제가 될 수 있더군요.
> >
> > 관심 갖지고 답변해준 동지님(?)들께 감사드립니다.
> >
> > --------------------------------------------------------------------------------
> >
> > 이 말이 정말입니까? 함수 파라미터의 주소값을 취할 때에는 특별히 주의해야
> > 하는 것인가요? 얼핏 보기에는 잘 이해가 안가는 부분입니다만...
>
>
> 일단 이런 근심을 하게되는 이유는 scope 내에 function prototype을
> 두지 않았기 때문인데 그런 기초적인 사항을 실수하고 이런 복잡한 내용을
> 이야기 하는게 조금 이상합니다만
>
> x86 리눅스에서와 M$ 윈도에서 테스트를 해봤는데 문제는 발생하지
> 않았습니다.
>
>
> > func(char zz) {
> > char *p, tmp;
> >
> > /* 밑에 분이 지적하신 오타를 수정했습니다. */
> > p = &zz /* (1) 좋은 방법이 아니다 */
> > tmp = zz;
> > p = &tmp /* (2) 훨씬 더 안전하다 */
>
> 이 부분을 보면 zz의 주소를 구하는 것은 좋은 방법이 아니라 하고 있는데
> 주소 값을 구하는 것 자체가 좋은 방법이고 아닌 방법이고 논할 바는 아니겠지요.
> 문제는 어떻게 쓰느냐인데 단순히 char 변수 가지고 주소를 1 증가 시킨다든지
> 하는 연산은 하지 않을 터이고 한다하면 다시 그 값을 참조 하는 일일진데
> 다시 참조한다 하여도 zz이 원래 가지고 있던 값이 나오겠지요.
>
> 즉 byte allignment가 문제시 된다면 zz의 포인터를 받아서 뭐하는게 문제가 아니라
> zz값 자체에 문제가 있어야 합니다. argument type promotion rule에 따라 char는
> int로 확장되어 어떤 endian 이냐에 따라 값이 딸라질 수 있다는 이야기를 하고픈
> 것인듯 싶은데 어쨌든 little endian 에서는 문제가 없군요.

KLDP BBS 에 가입하는 절차가 귀찮아서 (가입 안해도 포스팅할 수 있게 해
주면 좋으련만...) 메일로 OP 께 이미 간단히 답변드렸는데, 그 책에 대한
신뢰가 큰 것인지 사람들이 존재하지도 않는 문제를 보고 싶은 것 같습니
다. :(

다시 소스부터 보고 말씀 드리겠습니다.

    char z;
    func(z);

    func(char zz) {
       char *p, tmp;

       /* 밑에 분이 지적하신 오타를 수정했습니다. */
       p = &zz /* (1) 좋은 방법이 아니다 */
       tmp = zz;
       p = &tmp /* (2) 훨씬 더 안전하다 */

       /* ... */
    }

여기서 func() 가 원형 없이 implicit declaration 에 의해 호출되는 상황
을 가정하겠습니다. 그렇다면,

    extern int func();

과 같은 비원형 선언 아래에서 func(z); 의 호출이 이루어질 것이고, 이때
비원형 문맥이나 가변 인자 문맥에서 일어나는 기본 인자 진급이 적용됩니
다. 따라서, char 형의 인자 값은 int 형으로 변환되어 함수로 전달됩니다.
하지만, 중요한 것은 "함수 내부에서는 이렇게 전달받은 int 형의 값을 그
대로 사용하는 것이 아니라 다시 char 형으로 변환해 받아서 사용한다는
것" 입니다. 즉, 다음과 같은 과정이 이루어집니다.

char -> int -> int -> char

함수 func() 의 정의 자체가 비원형 호출 문맥에서도 호출될 수 있는 것이
기에 (즉, 표준이 비원형 문맥에서의 호출을 허락하고 있는 형태의 정의이
기에) implementation 은 func() 을 번역할 때 그 가능성을 배제할 수 없습
니다.

그렇다면, func() 안에서 zz 을 통해 받은 값은 결코 int 형이 될 수 없고
반드시 char 형이라는 이야기입니다 - 이는 해당 implemenation 이 표준을
따른다면 big-endian 이든 little-endian 이든 혹은 특정 데이터형의 정렬
제한이 어떻든 상관없이 반드시 보장이 되어야 하는 내용입니다. 즉, tmp
에 zz 을 한번 더 대입해 포인터로 가리키는 행동 자체가 전혀 무의미(!)하
다는 뜻입니다.

(IT 백두대간 C 언어, pp.536-539, pp.556-559, p.727)

그럼에도 불구하고 해당 저자가 그러한 내용을 책에 넣어놓은 이유는,

(1) 그 저자가 다른 부분에서는 __STDC__ 까지 들먹거리면서도 표준이 보장
하는 바를 제대로 이해하고 있지 못하다.

(2) 표준을 따르지 않는 (오래 전에 볼 수 있었던) implementation 을 고려
하고 있다.

중 하나라 볼 수 있습니다. 참고로 과거 (진짜 진짜 오래전) 일부
implementation 에서는 위의 예와 같은 함수 호출 문맥에서 기본 인자 진급
으로 확장된 int 형을 제대로 char 형으로 줄이지 못했기 (않았기) 때문입
니다. 참고로, 다음은 1984년 (표준 C 제정 전) 에 출판된 C 프로그래밍 스
타일과 관련된 책에서 인용한 것입니다.

Quote:

Taking the address of a function parameter can introduces
portability problems. In all environments, char and short
arguments are widened to int before being passed to a called
function. Several compilers also correspondingly widen parameter
declarations to int (so that the stack layout is not dependent on
byte-order).

그리고, 다음은 OP 에 의해 소개된 내용과 다음 책에서 나온 내용이 표준을
따르는 지금의 implemenation 에는 결코 적용되지 않음을 보이는 C90
Rationale 에서 인용한 것입니다.

Quote:

Some current implementations rewrite the type of, for instance, a
char parameter as if it were declared int, since the argument is
known to be passed as an int in the absence of a prototype. The
Standard requires, however, that the received argument be
converted as if by assignment upon function entry. Type rewriting
is thus no longer permissible.

물론, as-if 규칙에 의해서 (IT 백두대간 C 언어, pp.31-36) 특정
implementation 이 (특히, little endian 환경에서) 표준이 명시한 행동을
보장해줄 수 있다는 전제 아래에서 (따라서, 예로 든 C 프로그램은 영향 받
지 않습니다), 반드시 char 형 같은 narrow type 으로 줄이는 행동을 어셈
블리어 수준에서 보일 필요는 없습니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

unipro의 이미지

현재 사용되는 모든 컴파일러들이 최소한 이 문제에 있어서 완벽하게 표준을 지킬 경우에 그럴 필요가 없겠지만, 이것에 대해서는 저는 잘 모르겠습니다.

기본적으로 프로그래밍을 할때, 무엇을 단정지어서 하는 것을 별로 좋지 않다고 배웠습니다. 유연성을 가지는 프로그램을 작성하는 것은 유닉스 철학중에 포함되더군요. 시스템에 따라서 문제가 될 수 있는 부분이 발견되고 이것이 확실히 처리된다는 보장이 없으면, 프로그래밍 내에서 확실히 처리가 되도록 해주는 것이 좋은 선택이라고 생각합니다.

어쨌든 님께서 적어주신 내용으로 새로운 정보들을 알게 되어서 고맙습니다.

내 블로그: http://unipro.tistory.com

전웅의 이미지

unipro wrote:
현재 사용되는 모든 컴파일러들이 최소한 이 문제에 있어서 완벽하게 표준을 지킬 경우에 그럴 필요가 없겠지만, 이것에 대해서는 저는 잘 모르겠습니다.

C 표준이 제정된 지도 벌써 13년이 지났으며, 벌써 한번의 개정 (1999년)
이 있었습니다. 임베디드 분야에서 사용되는 거의 모든 컴파일러도 최소한
ANSI-C (C90) 를 따른다고 주장하고 있으며, 15년 이상된 DOS 환경의 컴파
일러들도 표준 초안 (C90 draft) 을 따른다고 하고 있습니다. 얼마나 낙후
된 환경을 접해야 표준을 따르지 않는 컴파일러를 만날 수 있을지 의문입니
다.

결국, "표준을 따른다" 고 주장하는 컴파일러에서 위와 같은 문제가 발견된
다면 이는 해당 vendor 에게 정당하게 수정을 요청할 수 있는 부분입니다 -
아니면 최소한 "표준을 따른다" 는 주장을 철회하라고 요구할 수는 있습니
다.

unipro wrote:
기본적으로 프로그래밍을 할때, 무엇을 단정지어서 하는 것을 별로 좋지 않다고 배웠습니다. 유연성을 가지는 프로그램을 작성하는 것은 유닉스 철학중에 포함되더군요. 시스템에 따라서 문제가 될 수 있는 부분이 발견되고 이것이 확실히 처리된다는 보장이 없으면, 프로그래밍 내에서 확실히 처리가 되도록 해주는 것이 좋은 선택이라고 생각합니다.

좋은 철학이며 동의합니다만, ISO/IEC 수준의 오래된 국제 표준이 있음에도
그리 걱정할 것이 많다면 UNIX-like 환경에서 작성하는 프로그램 한줄 한줄
모두가 불분명해질 수 밖에 없습니다 - 어떻게 한 부분은 표준을 따르지 않
을 수 있다고 생각하면서 다른 많은 부분은 표준을 (최소한 일반적인 예상
을) 따른다고 가정할 수 있겠습니까? 만약, 해당 저자가 혹시라도 그 책의
개정판을 낸다면 그 고리타분한 내용을 다루는 부분은 삭제되어야 마땅합니
다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

체스맨의 이미지

저 예제는 저자로서도 당위성을 주장한 것이 아니라, tip 정도의 의미라고
봅니다. 일말의 가능성이 있다는 것이죠. 이런 경우도 있으니, 고려하려면
하고, 하기 싫으면 말고... 정도 겠죠.

그래서,
"저자가 다른 부분에서는 __STDC__ 까지 들먹거리면서도 표준이 보장 하는 바를 제대로 이해하고 있지 못하다. "
라고까지 받아들이기는 어렵습니다. 또한 C 표준은 대개 문법과 함수에 대한
정의지, 실행시 반영되는 스택 프레임이나, promotion 까지는 그 범주라
보기 어렵습니다.

"UNIX-like 환경에서 작성하는 프로그램 한줄 한줄 모두가 불분명해질 수
밖에 없습니다"
이 말씀도 받아들이기 어렵습니다.
Unix-like 뿐 아니라, 모든 C 컴파일러를 생각한다면 어떤 부류의
사람에게서는 충분히 받아들여질 수 있는 좋은 tip 이라 생각되구요.
저런 tip 으로 인해 한 줄 한 줄이 불분명해질만큼 C 가 불분명한 언어는
아니라고 생각합니다.

저 책은 2판까지 나온 것으로 알고 있습니다.
3판에서 삭제될 진 모르겠으나, 저라면 안지울 것 같습니다.
저로서는 좋은 예제라고 봅니다.

Orion Project : http://orionids.org

전웅의 이미지

체스맨 wrote:
저 예제는 저자로서도 당위성을 주장한 것이 아니라, tip 정도의 의미라고
봅니다. 일말의 가능성이 있다는 것이죠. 이런 경우도 있으니, 고려하려면
하고, 하기 싫으면 말고... 정도 겠죠.

제 주장은 그 "알말의 가능성" 이라는 것을 현실적으로는 더 이상 찾아볼
수 없다는 뜻입니다. 현재 상업적으로 사용되는 제가 아는 모든 컴파일러는
표준 (최소한 C90 이상) 을 따른다고 주장하고 있으며, 일부 교육용이나 실
험적으로 개발된 독특한 컴파일러만이 심각하게 표준을 못 따르고 있을 뿐
입니다. 가능하면 그 "일말의 가능성" 이라는 것을 구체적으로 확인해 보고
싶습니다. "현재" 사용되는 "상업용" 컴파일러 중에 C 표준을 따르지 않는
다고 명백히 밝히는 컴파일러가 있는지요?

체스맨 wrote:
그래서,
"저자가 다른 부분에서는 __STDC__ 까지 들먹거리면서도 표준이 보장 하는 바를 제대로 이해하고 있지 못하다. "
라고까지 받아들이기는 어렵습니다.

저는 이전 글에서 분명 두 가지 가능성을 제시했습니다. 다른 한 가능성은
"매우 오래된 표준을 따르지 않는 implementation 을 고려하고 있는 듯 하
다" 는 것이었습니다.

체스맨 wrote:
또한 C 표준은 대개 문법과 함수에 대한
정의지, 실행시 반영되는 스택 프레임이나, promotion 까지는 그 범주라
보기 어렵습니다.

스택 프레임 같은 것은 표준이 명시할 필요도 없습니다. 어차피 추상적으로
언어를 정의하는 것이며, implementation 은 어떤 구체적 방법을 사용해서
든 그 추상적 정의를 만족하기만 하면 되는 것입니다 - 이것이 바로 제가
언급한 as-if rule 이 의미하는 바입니다. 표준에 대해 심각하게 오해하고
계신듯 합니다. 제가 이전에 포스팅했던 글의 마지막 부분을 보십시오. 실
제 little-endian 을 사용하는 implementation 에서는 실제 구현 과정에
int 형으로 전달받은 값을 char 형으로 좁힐 필요가 없으며, big-endian 환
경이라고 해도 그러한 상황에서는 간단히 매개변수의 주소를 변경하는 것으
로 구현될 수 있습니다. 두 경우 모두 표준의 추상적 정의를 분명히 만족하
고 있으며, 책에 제시된 상황이 결코 문제가 될 수는 없습니다.

그리고 표준은 promotion 을 정의하고 있습니다 - 해당 부분은 기본 인자
진급 (default argument promotion) 에 의해 기술됩니다.

체스맨 wrote:
"UNIX-like 환경에서 작성하는 프로그램 한줄 한줄 모두가 불분명해질 수
밖에 없습니다"
이 말씀도 받아들이기 어렵습니다.
Unix-like 뿐 아니라, 모든 C 컴파일러를 생각한다면 어떤 부류의
사람에게서는 충분히 받아들여질 수 있는 좋은 tip 이라 생각되구요.
저런 tip 으로 인해 한 줄 한 줄이 불분명해질만큼 C 가 불분명한 언어는
아니라고 생각합니다.

C 표준은 (표준을 따른다고 주장하는) "모든 C 컴파일러" 를 위한 것입니
다. 또한, 누가 C 가 불분명한 언어가 아니라고 정의해 준다고 생각하십니
까? 이는 바로 표준이 하는 일입니다. 표준의 일부분은 신뢰할만 하지만,
다른 일부분은 그럴 수 없다는 생각 자체가 그릇된 것임을 지적하는 것입니
다. 또한, UNIX-like 환경을 이야기한 것은 OP 께서 UNIX 환경을 언급했기
때문이며, 특히나 POSIX 가 C 표준을 normative reference 로 참조하고 있
기 때문이기도 합니다.

예를 들어, 표준을 따르지 않는 implementation 에서 다음 프로그램의 출력
결과가 무엇이 되리라 예상하십니까?

int main(void)
{
printf("Hello, world!\n");

return 0;
}

또 그 결과를 누가 보장해 주지요? 만약, 제가 위 프로그램을 "HELLo,
tHERE!" 라는 결과를 출력하도록 번역해주는 "표준을 따르지 않는" 컴파일
러를 만든다면 제가 무엇을 위반한 것인지요?

표준을 부분적으로 따르는 것은 (그것을 표준이 허락해 주지 않는 이상 -
예를 들면, C99 의 ISO/IEC 60559 연산 지원은 optional 입니다) 표준을
따르는 것이 아닙니다.

체스맨 wrote:
저 책은 2판까지 나온 것으로 알고 있습니다.
3판에서 삭제될 진 모르겠으나, 저라면 안지울 것 같습니다.
저로서는 좋은 예제라고 봅니다.

원하신다면, 제가 직접 저자에게 연락해 보겠습니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

체스맨의 이미지

제생각에는 님께서 저자가 의도한 tip 을 tip 으로 받아들이지 않으시는
것 같다는 생각도 드는데요.

표준 이전에 만들어진 컴파일러 들도 있고,
개인적인 즐거움을 위해 그것을 이용하는 사람들도 있습니다.
상업적인 용도만 고려하고 싶진 않군요.

컴파일러 버그가 있을 수도 있고, 버그가 표준을 침해할 수도 있고,
그 버그를 수정하기 전에 vendor 가 망해서 사라지는 경우도 있지요.
그 상황에서도 그 컴파일러를 이용해야 하는 경우도 있구요.

저로서는 말씀처럼 표준에 대해 심각하게 오해하고 있는 것이 아니라,
표준이 아닌 것도 고려하고 싶다는 게 맞습니다.

물론 여기에 대해서는 님께서 어떤 반론을 제기하실 줄은
대충 알겠습니다만, 우선 C 라는 범주로 한정하고, 일부의
구현이 표준과 다른 경우라고 말씀드려야 하겠습니다.
상식적인 수준에서 C 로 인정되는 경우라고 말씀드려야 겠군요.
님께서는 비논리적이라 생각하시겠지만요. 유명한 상업적
컴파일러인 MS 의 제품만해도 완전히 표준을 따르고 있다고 보기는
어렵거든요.

"실제 little-endian 을 사용하는 implementation 에서는 실제 구현 과정에
int 형으로 전달받은 값을 char 형으로 좁힐 필요가 없으며, big-endian 환
경이라고 해도 그러한 상황에서는 간단히 매개변수의 주소를 변경하는 것으
로 구현될 수 있습니다. "
이 부분은 이미 저도 알고 있고, 저도 언급했습니다. 어쨌든 님의 의견도
충분히 이해 합니다.

그리고 기본 인자의 진급 (promotion) 부분이 표준 (ANSI,ISO 등)에
기술된 보다 구체적인 위치를 알려주셨으면 합니다. 그 부분은
저도 찾아보고 싶네요.

그리고, 직접 저자에게 연락해보시겠다는 것은 매우 흥미로운 일입니다.
그렇게 하실 의향이 있으시면 전 그것을 원합니다.
결과를 기대하겠습니다.

Orion Project : http://orionids.org

전웅의 이미지

체스맨 wrote:
제생각에는 님께서 저자가 의도한 tip 을 tip 으로 받아들이지 않으시는
것 같다는 생각도 드는데요.

아닙니다. tip 으로 보고 있습니다. 하지만, 그 tip 의 유효성이 상당히 떨
어진다는 것을 문제 삼고 있는 것입니다. 또한, tip 을 나열하는 다른 부분
에서는 표준에 대해 언급하면서, 해당 tip 은 "표준을 따르지 않는"
implementation 에서만 유용함에도 불구하고 그러한 사실을 제대로 알리지
않은 부분을 지적하고 싶은 것입니다. 만약, 그 tip 을 보이면서, "일부 표
준을 따르지 못하는 implementation 에서는 다음과 같은 문제가 있을 수 있
다" 라고 밝혔다면 아무런 문제도, 또 OP 께서도 의심할 필요가 없었을 것
입니다. 참고로 제가 이전에 인용해 드린 (표준 제정 이전에 출판된) 책 역
시 개정되면서 그런 부가적인 설명을 덧붙였습니다.

체스맨 wrote:
표준 이전에 만들어진 컴파일러 들도 있고,
개인적인 즐거움을 위해 그것을 이용하는 사람들도 있습니다.
상업적인 용도만 고려하고 싶진 않군요.

예, 그렇습니다.

체스맨 wrote:
컴파일러 버그가 있을 수도 있고, 버그가 표준을 침해할 수도 있고,
그 버그를 수정하기 전에 vendor 가 망해서 사라지는 경우도 있지요.
그 상황에서도 그 컴파일러를 이용해야 하는 경우도 있구요.

버그를 수정하기 전에 vendor 가 망한 경우라면 사실 그 컴파일러는 표준을
따를 수 없는 것으로 봐야 하며, 표준을 따른다고 주장하면서 버그에 의해
표준을 따르지 못하는 경우라면 말씀드렸듯이 "표준을 따른다" 라는 주장을
철회하거나 (주장대로 표준을 따르기 위해서는) 버그를 수정해야만 합니다.

제가 계속해서 표준과 컴파일러 이야기를 할 때, "표준을 따른다고
*주장하는*" 이라는 표현을 사용했다는 점에 유의해 주시기 바랍니다. 말씀
하신대로 모든 표준을 따른다고 주장하는 implementation 이 표준을 따르는
것은 아닙니다.

체스맨 wrote:
저로서는 말씀처럼 표준에 대해 심각하게 오해하고 있는 것이 아니라,
표준이 아닌 것도 고려하고 싶다는 게 맞습니다.

물론 여기에 대해서는 님께서 어떤 반론을 제기하실 줄은
대충 알겠습니다만, 우선 C 라는 범주로 한정하고, 일부의
구현이 표준과 다른 경우라고 말씀드려야 하겠습니다.
상식적인 수준에서 C 로 인정되는 경우라고 말씀드려야 겠군요.
님께서는 비논리적이라 생각하시겠지만요. 유명한 상업적
컴파일러인 MS 의 제품만해도 완전히 표준을 따르고 있다고 보기는
어렵거든요.

그렇기 때문에 MS 에서는 "형식적으로나마" bug report 를 받고 있습니다.
사실 MS 가 표준을 따른다고 주장하든 그렇지 않든 표준 C 언어를 이야기할
때 개인적으로 MSVC 는 생각하고 싶지 않습니다. :(

int main(void)
{
    return 0 && 1 / 0;
}

표준을 따른다고 주장하면서 이 프로그램을 reject 하는 멍청한 컴파일러가
MSVC 입니다.

체스맨 wrote:
그리고 기본 인자의 진급 (promotion) 부분이 표준 (ANSI,ISO 등)에
기술된 보다 구체적인 위치를 알려주셨으면 합니다. 그 부분은
저도 찾아보고 싶네요.

C99 6.5.2.2p6,7 (C90 6.3.2.2)
C99 6.9.1p3 (C90 6.7.1)

그리고 C99 6.9.1p3 을 인용한 이유는 다음 wording 때문입니다:

If the declarator includes a parameter type list, the list also
specifies the types of all the parameters;

즉, 선언된 매개변수의 type 은 함부로 implementation 이 widen 할 수 없
습니다.

체스맨 wrote:
그리고, 직접 저자에게 연락해보시겠다는 것은 매우 흥미로운 일입니다.
그렇게 하실 의향이 있으시면 전 그것을 원합니다.
결과를 기대하겠습니다.

가능하면 오늘 중으로 메일 보내겠습니다 - 그런데, 책에 저자 이 메일이
나와 있습니까? 지금 책을 가지고 있지 않아서...

혹시나 메일이 "씹히면" 씹혔다고라도 사실을 알려드리겠습니다. :)

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.