C언어 기억부류 지정자에 대해서 궁금한게 있습니다
글쓴이: gurumong / 작성시간: 수, 2007/03/28 - 3:50오전
C언어 기억부류 지정자에 대해서 궁금한게 있습니다
Quote:
내부 연결을 갖도록 선언된 명칭은
혹시나 다른 프로그램 소스가 선언했을지 모르는 동일한 명칭과 충돌을 일으키지 않도록
해당 프로그램 소스 안에서 고유의 의미로 사용할 수 있도록 허락해준다
인쿨루드시킨 헤더파일 또는 링크될 오브젝트 모듈에
extern 기억부류자를 가지고 혹은 기억부류지정자 없이 파일 통영범위로 선언된
외부연결을 가지는 명칭과의 충돌을 이야기 하는것 같은데요
연결과 관련해서는 명칭의 선언순서가(어떤 기억지정부류자를 갖고 먼저 선언되는지) 중요한걸로 알고있는데
그럼 있을지도 모르는 명칭의 충돌을 방지 하기 위해서는
인쿨루드문 보다 앞서서 static 기억부류지정자를 가지고 명칭을 선언해야하는것인가요?
제가 잘 이해한것인지 잘 모르겠습니다
제가 읽는 책에 아무런 언급이 없어서
프로그램 어딘가에 하나의 소스파일내에 외부 연결을 갖는 명칭이 선언되면
나머지 소스파일에서는 그 명칭에 대한 아무런 선언없이 그냥 사용하면 되는줄 알았는데
다른 소스파일에서도 같은 명칭으로 외부연결로 선언해야 사용할수있더라구요
원래 이렇게 사용하는게 맞는지요?
그리고 이런식으로 프로그램 전체에 걸쳐서 사용될 명칭에 대해서
모든 소스에 외부연결을 가지는 명칭으로 선언해야한다면
초기화가 필요할때 모든 소스파일의 그 명칭의 선언에서 초기화도 같이 해주어야하는것인가요?
ㅜ.ㅜ
Forums:
무슨 말인지 용어가 좀..
쓰신 용어들 중 처음보는 용어가 많군요.
기억부류자... 변수를 이야기하시는 건가요?
외부 연결이라 함은 외부 선언? 다른 파일에서 선언한 전역 변수나 함수?
전역변수의 예를 들면 초기화는 한 곳에서만 하셔야 합니다.
물론 extern 선언은 변수를 이용하고자하는 모든 파일에 있어야 하고요.
그래서 보통 초기화는 .c 파일에서 하고요, extern 선언은 .h (헤더) 파일에 넣습니다.
선언과 정의의 관계
>>인쿨루드문 보다 앞서서 static 기억부류지정자를 가지고 명칭을 선언해야하는것인가요?
>>제가 잘 이해한것인지 잘 모르겠습니다
명칭에 대한 충돌이 발생시 Header 파일들(표준, 제3자, 사용자헤더)에 있는 명칭들을 수정하기는 불가능할 겁니다.
대신, static한 명칭을 변경하는 것이 수월합니다.
기존과 같이, 소스(.c 파일)에 Header파일을 기술한 후에 추가 선언들을 기술하고 추가 정의를 기술하시기 바랍니다.
>>초기화가 필요할때 모든 소스파일의 그 명칭의 선언에서 초기화도 같이 해주어야하는것인가요?
선언에서 명시적 extern속성 갖는 초기화(정의)를 할 수 없습니다.
extern 속성으로 동일한 명칭을 다른 소스에서 초기화(정의)하였다면,
컴파일시는 개별적으로 컴파일 되기 때문에 오류가 발생하지 않지만, 링크시에 중복 오류를 발생합니다.
linkage에 대해서는 이전에도 질문한것 같은데, 그곳에서 찾아보면 관련 내용들 있는 것 같습니다.
-- 덧붙이는 글 --
선언과 정의의 관계를 이해하시면 될 것 같습니다.
> C언어 기억부류
> C언어 기억부류 지정자에 대해서 궁금한게 있습니다
>
> 인용:
> 내부 연결을 갖도록 선언된 명칭은
> 혹시나 다른 프로그램 소스가 선언했을지 모르는 동일한 명칭과 충돌을 일으키지 않도록
> 해당 프로그램 소스 안에서 고유의 의미로 사용할 수 있도록 허락해준다
>
> 인쿨루드시킨 헤더파일 또는 링크될 오브젝트 모듈에
> extern 기억부류자를 가지고 혹은 기억부류지정자 없이 파일 통영범위로 선언된
> 외부연결을 가지는 명칭과의 충돌을 이야기 하는것 같은데요
>
외부연결(external linkage)을 가진 명칭과 내부연결(internal linkage)을
가진 명칭이 동일한 명칭일 경우 표준에 의하면 문제가 될 수 있습니다.
이 문제는 lovewar 님 말씀대로 과거에도 한번 나온 이야기이므로 생략
하겠습니다.
연결(linkage)은 유효범위(혹은 통용범위, scope)와 마찬가지로 어떤
명칭이 영향력을 갖는 범위를 제한하기 위한 도구입니다.
예를 들어, scope 를 통해 어떤 명칭이 특정 블록 내에서만, 혹은 특정
함수 안에서만, 혹은 특정 소스 파일 안에서 보이도록(영향력을 갖도록)
만드는 것이 가능합니다. 하지만, 최대로 큰 scope 이 파일(정확히는
translation unit) 하나에 밖에 못미치기 때문에 여러 소스 파일로 하나
의 프로그램을 구성하는 경우를 위해 여러 파일에 영향을 미치는 명칭을
만들 수 있는 방법이 필요합니다. 이때 활약하는 것이 바로 연결
(linkage)입니다 - 즉, 외부 연결은 해당 프로그램을 구성하는 모든
파일에 영향을 미치는 명칭을 위해, 내부 연결은 file scope 이지만
하나의 소스 파일 안으로 영향력이 제한되는 명칭을 위해 사용한다고
생각하시면 됩니다.
그 외 자잘한 주의 사항은 책의 "외부 정의" 부분에서 다루고 있으므로
생략하겠습니다.
> 연결과 관련해서는 명칭의 선언순서가(어떤 기억지정부류자를 갖고 먼저 선언되는지) 중요한걸로 알고있는데
> 그럼 있을지도 모르는 명칭의 충돌을 방지 하기 위해서는
> 인쿨루드문 보다 앞서서 static 기억부류지정자를 가지고 명칭을 선언해야하는것인가요?
> 제가 잘 이해한것인지 잘 모르겠습니다
>
#include 에 의해 포함되는 파일은 사실상 해당 부분에 첨가되어 그 소스
파일을 구성하는 부분으로 보시면 됩니다. 구체적으로 어떤 경우를 의미
하는 것인지 이해하기 힘들어 보다 자세한 답변을 드리기가 어렵네요.
> 제가 읽는 책에 아무런 언급이 없어서
과연 그럴까요? ;-)
> 프로그램 어딘가에 하나의 소스파일내에 외부 연결을 갖는 명칭이 선언되면
> 나머지 소스파일에서는 그 명칭에 대한 아무런 선언없이 그냥 사용하면 되는줄 알았는데
> 다른 소스파일에서도 같은 명칭으로 외부연결로 선언해야 사용할수있더라구요
> 원래 이렇게 사용하는게 맞는지요?
>
> 그리고 이런식으로 프로그램 전체에 걸쳐서 사용될 명칭에 대해서
> 모든 소스에 외부연결을 가지는 명칭으로 선언해야한다면
> 초기화가 필요할때 모든 소스파일의 그 명칭의 선언에서 초기화도 같이 해주어야하는것인가요?
>
그렇지 않습니다. 일반적으로 "정의는 하나만 존재한다"는 원칙을 생각
하시면 됩니다. 아마도 아직 연결과 외부 정의(external definition),
임시 정의(tentative definition) 등을 다루는 부분을 보지 않으신 것
같습니다. (제 기억이 맞다면) 가장 마지막 장에 설명되어 있습니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
그러니까...
보통은 코딩을...
가장 먼저 인쿨루드 문을 넣고, 아래에 전역변수와 함수원형을 선언하고, 그 아래로 함수들을 이쁘장하게 정의를 하는데
사용하려는 전역변수의 명칭이 뜻하지 않게 이미 만들어져 제공되는 인쿨루드하는 헤더파일내에 선언되어 있을경우 명칭의 충돌이 일어나는데
위와 같이 하나의 명칭이 같은 파일통용범위내에 static와 extern 기억부류자를 모두 가지고 선언되어있다면
먼저 선언된쪽의 기억부류자에 따라서 내.외부 연결이 결정되는것이 맞나요?
규칙엔 extern 기억부류지정자를 기준으로 설명을 하고 있는데
뒤쪽에서 다시 선언되는 명칭이 블럭내에 있지 않고
같은 통영범위내에 있을때에도 규칙에 따라 연결을 물려받게 되는지 궁금해서요
(예제엔 그런식의 선언을 다루고 있지 않아서...)
> 보통은 코딩을... >
> 보통은 코딩을...
> 가장 먼저 인쿨루드 문을 넣고, 아래에 전역변수와 함수원형을 선언하고, 그 아래로 함수들을 이쁘장하게 정의를 하는데
> 사용하려는 전역변수의 명칭이 뜻하지 않게 이미 만들어져 제공되는 인쿨루드하는 헤더파일내에 선언되어 있을경우 명칭의 충돌이 일어나는데
>
명칭의 충돌이 발생했을 때 중요한 기준은 충돌한 두 명칭이 사실 2개의
서로 "다른" 개체(변수, 함수 등)를 의미하는 것인지, 아니면 사실은
동일한 개체를 의미하는 것인지 입니다. 이런 사실 확인 없이 무조건 내부
명칭으로 선언되도록 강제했다고 해서 원하는 바가 이루어지는 것은
아닙니다.
> 위와 같이 하나의 명칭이 같은 파일통용범위내에 static와 extern 기억부류자를 모두 가지고 선언되어있다면
> 먼저 선언된쪽의 기억부류자에 따라서 내.외부 연결이 결정되는것이 맞나요?
>
> 규칙엔 extern 기억부류지정자를 기준으로 설명을 하고 있는데
> 뒤쪽에서 다시 선언되는 명칭이 블럭내에 있지 않고
> 같은 통영범위내에 있을때에도 규칙에 따라 연결을 물려받게 되는지 궁금해서요
> (예제엔 그런식의 선언을 다루고 있지 않아서...)
>
예제엔 나오지 않지만 명칭의 연결을 결정하는 규칙 ("1. 어쩌구, 1-1.
저쩌구" 하는 식으로 기술되어 있는 규칙) 을 보시면 아래와 같은 경우
첫번째 선언에 의해 명칭의 연결이 결정된다는 사실을 쉽게 확인하실 수
있습니다 - 결국, it_is_a_really_static_variable 은 내부 연결을 갖게
됩니다. 이를 놓고 혹자는 extern 이라는 키워드가 2개의 의미 (이전
선언의 연결을 물려받음 vs. 외부 연결로 선언함) 를 갖기 때문이라고
설명하기도 합니다.
하지만, #include 와 관련해 말씀하신 상황이 진정 아래와 같은 상황
이라면... (아래에서 libheader.h 는 다른 라이브러리 등에서 제공하는
헤더라 가정합니다)
님이 사용하려는 명칭과 libheader.h 에서 선언해 사용하고자 하는 명칭이
서로 "다른" 개체를 의미하기 위한 것이 됩니다. 즉, 님은 님대로,
라이브러리는 라이브러리대로 자신만의 변수나 함수 등을 의미하기 위해
같은 명칭을 사용하려는 경우가 되므로, (라이브러리 코드를 직접 수정할
수 없는 이상) 불가피하게 님이 명칭을 양보해야 합니다.
위와 같이 libheader.h 첨가 이전에 static 선언을 주었다 해서 해당 소스
파일 안에서 lib_ext_flag 라는 명칭을 님 마음대로 사용할 수 있음을
의미하는 것이 결코 아닙니다 - 아래 내용을 생각해 보시기 바랍니다.
#1 만약, 님이 사용하려는 명칭의 의미와 헤더에서 사용하고 있는 명칭의
의미가 (단순히 연결의 차이만 있는게 아니라) 완전히 다를 경우엔
어떻게 하시겠습니까?
#2 "우연히" 둘의 의미(type 등)가 동일하다고 해도 다른 모듈
(라이브러리)에서 lib_ext_flag 를 외부 연결로 "정의"해 사용하고,
"같은" 프로그램을 구성하는 "다른" 파일에서 이를 내부 연결로
정의해 사용하는 것은 "정의되지 않은" 행동에 해당합니다 - 이는
내부 연결로 명칭을 정의해 사용하는 경우에도 명칭 선택에 신중을
기해야 함을 의미합니다.
#3 "우연히" 둘의 의미도 동일하고, "우연히" implementation 에서 동일한
명칭을 ("다른" 개체를 의미하기 위해) 각각 외부 연결, 내부 연결로
정의해 사용하는 것을 허락한다고 해도 문제가 없는 것은 아닙니다.
예를 들어, 해당 헤더 내에 라이브러리가 다음과 같은 매크로를 제공
하고 있고
해당 소스 파일의 코드 상에서 SET_AND_TEST_FLAG() 매크로가 실행될
경우 이는 라이브러리가 관리하는 외부 연결 명칭의 변수가 아니라
님이 관리하는 내부 연결 명칭의 변수가 수정되는 원치않는 결과를
낳게 됩니다.
결론적으로, 님이 통제할 수 없는 모듈을 사용하고, 그 모듈이 외부 연결
명칭을 사용한다면, 님의 코드에서는 그 명칭을 (외부 연결은 물론) 내부
연결로 정의해 사용할 수 없습니다. 보다 바람직하게는 아예 다른 의미
로는 사용하지 않아야 합니다 - 따라서 그만큼 공통적으로 쓰일 수 있는
라이브러리를 구현할 때는 외부 연결 혹은 내부 연결의 명칭을 신중히
선택해야 합니다.
덧붙여 표준 헤더를 포함해 모든 헤더 파일을 #include 하기 전에는
(반드시 필요한 매크로 정의 등을 제외하고) 어떤 선언이나 정의도 나오지
않도록 하는 것이 좋습니다.
이런 저런 내용이 섞여 있어 잘 설명이 되었는지 모르겠네요. 추가로 궁금
하신 부분 다시 질문주시면 답변 드리겠습니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
static이 우선되는군요.
우선 컴파일은 파일단위로 이루어 집니다.
extern키워드는 현재 컴파일 단위인 파일에서 정의 되어있지 않은 변수(심볼)을 땡겨오기 위해 사용합니다.
이 파일에는 없지만 어딘가에 있으니 나중에 해결되니 머 대충 컴파일해죠... 머 이런뜻??
그럼 나중에 링킹시에 해당 변수가 실제 존재하는 오브젝트의 공간을 가르키도록 되는거죠.
그래서 오브젝트파일에 땡겨오는 심볼들의 이름이 기록됩니다. 나중에 링킹시에 땡겨오기 쉽게 하기위해서..
땡겨오는 심볼들의 테이블이 존재합니다. XXX심볼테이블이라고 했는데 기억이 안나네요..
반대로, 우리가 전역으로 선언(공간할당)하는 변수들은 다른 파일에서 참조할수 있도록(줄수있도록)
또한 심볼에 대한 정보가 관리됩니다. 이것들은 남들이 가져갈수 있는 것들입니다.
적어도 두개의 심볼테이블을 가지고 있습니다. import,export...
링킹시에 동일 명의 전역변수가 여러 오브젝트에서 선언되어있다면 이는 땡겨가야하는 오브젝트에서 어느 놈을 가져가야할지
난감하겠죠... 이럴경우 링킹시에 중복되어 정의 되어 있는 심볼이 있다며 링킹시 에러메시지를 출력합니다.
반대로 땡겨가는 놈들은 있는 주는 놈이 없을경우 정의 되지 않은 심볼이 있다거나 혹은 해결되지 않은 심볼이 있다면 에러 메시지를
띄웁니다.
static키워드는 이렇게 남들에게 줄수있는 심볼테이블에 해당 변수이름을 등록하지 않고,
해당 오브젝트를 컴파일할때만 사용하고 심볼정보를 버려버리도록 합니다.
그러므로 statice키워드로 정의한 심볼은 여러파일에서 중복해서 정의 할수있는거죠.
왜냐면 링킹시에 이 심볼들은 안보이니까요...
그럼 extern으로 땡겨오고 static으로 재 정의한 동일 심볼은 어떻게 될까?
저도 흠.... 방금 VS6으로 한번 만들어 밨습니다.
-------------
int a=10;
void b();
int main()
{
b();
}
-------------
static int a=20;
extern int a;
void b()
{
a++;
}
-------------
static선언과 extern선언이 바뀌어도 결과는 21이더군요...
static우선되는것 같습니다.
결과를 보고 상식적으로 생각해보니까 맞는것 같기도하고....
그래도 될수 있으면 extern으로 땡겨오늘 구문과 중복되는건 별로 좋지 않을듯 하네요.
------------------------------
lol
------------------------------
lol
> 그럼 extern으로
> 그럼 extern으로 땡겨오고 static으로 재 정의한 동일 심볼은 어떻게 될까?
> 저도 흠.... 방금 VS6으로 한번 만들어 밨습니다.
>
> -------------
> int a=10;
> void b();
> int main()
> {
> b();
> }
> -------------
> static int a=20;
> extern int a;
>
> void b()
> {
> a++;
> }
> -------------
두번째 파일에서 extern int a; 는 "절대로" 첫번째 파일의 a 를
"끌어오겠다"는 의미로 받아들여지지 않습니다 - 저 위에 답변 적느라 저
나름대로 시간 많이 썼습니다, 한번쯤 읽어봐 주시기 바랍니다. 두번째
파일에서 extern int a; 는 "있으나 마나"한 선언입니다!
> static선언과 extern선언이 바뀌어도 결과는 21이더군요...
>
> static우선되는것 같습니다.
> 결과를 보고 상식적으로 생각해보니까 맞는것 같기도하고....
>
> 그래도 될수 있으면 extern으로 땡겨오늘 구문과 중복되는건 별로 좋지 않을듯 하네요.
>
"될 수 있으면"이 아니라 "잘못된" 프로그램입니다. 위에서도 언급했고
아래에서도 논의된 바 있습니다. (lovewar 님과의 논의를 보시기
바랍니다)
http://kldp.org/node/75510
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
네~ 꼼꼼하게
네~ 꼼꼼하게 읽어보도록 하겠습니당 ^^;
------------------------------
lol
------------------------------
lol
명칭의 의미가(타입)
명칭의 의미가(타입) 다를경우와 명칭에 대해 매크로가 있을경우에문제를 일으킨다고 설명해주셨는데요
> #2 "우연히" 둘의 의미(type 등)가 동일하다고 해도 다른 모듈
> (라이브러리)에서 lib_ext_flag 를 외부 연결로 "정의"해 사용하고,
> "같은" 프로그램을 구성하는 "다른" 파일에서 이를 내부 연결로
> 정의해 사용하는 것은 "정의되지 않은" 행동에 해당합니다 - 이는
> 내부 연결로 명칭을 정의해 사용하는 경우에도 명칭 선택에 신중을
> 기해야 함을 의미합니다.
>
이 부분에서 잘 이해가 가지 않습니다
설명에는 정의되지 않은 행동에 해당한다는 표현이 있어서 표준에 어긋난다는 의미로 쓰신거 같은데
하나의 명칭이 각기 다른 모듈에서 내부 연결과 외부연결로 다르게 정의하는것이 어떤 문제를 일으킬수있나요??
내부 연결을 가지게 되면 링커에게 명칭이 알려지지 않으니
겉보기엔 서로 외부 연결로 선언해놓고 한쪽 모듈에서 그 명칭을 사용하지 않는 것과 다름이 없지 않나 생각되는데요
프로그램 전체에 걸쳐서 사용될 명칭이 그 일부인 어떤 하나의 소스에서 사용되지 않을경우
물론 "올바르지는" 않지만 우연히 같은 타입인데다가 꼭 그 명칭을 써야겠다고 생각되면
헤더 파일이 인쿨루드 되는 기점 보다 앞서 내부연결로 선언하는것이 연결이 결정되는 규칙에 따라 문제가 없을꺼 같은데요
(설명해주신 명칭의 의미가 다르거나 매크로에 사용되지 않았다고 가정했을때에)
제가 그렇게 프로그래밍을 하겠다는것이 아니라 표준에 대해서 좀더 알고 싶어서 질문드리는것입니다 흠;
전 제 질문을 정리하고 글을 쓰는데에도 시간이 꽤나 걸리던데
한참 장문인 답변을 써주시는데 정말로 감사하게 생각하고있습니다 T.T
> 명칭의
> 명칭의 의미가(타입) 다를경우와 명칭에 대해 매크로가 있을경우에문제를 일으킨다고 설명해주셨는데요
>
당연히 그럴 수밖에 없습니다.
> > #2 "우연히" 둘의 의미(type 등)가 동일하다고 해도 다른 모듈
> > (라이브러리)에서 lib_ext_flag 를 외부 연결로 "정의"해 사용하고,
> > "같은" 프로그램을 구성하는 "다른" 파일에서 이를 내부 연결로
> > 정의해 사용하는 것은 "정의되지 않은" 행동에 해당합니다 - 이는
> > 내부 연결로 명칭을 정의해 사용하는 경우에도 명칭 선택에 신중을
> > 기해야 함을 의미합니다.
> >
>
> 이 부분에서 잘 이해가 가지 않습니다
> 설명에는 정의되지 않은 행동에 해당한다는 표현이 있어서 표준에 어긋난다는 의미로 쓰신거 같은데
>
넵, 맞습니다.
> 하나의 명칭이 각기 다른 모듈에서 내부 연결과 외부연결로 다르게 정의하는것이 어떤 문제를 일으킬수있나요??
> 내부 연결을 가지게 되면 링커에게 명칭이 알려지지 않으니
> 겉보기엔 서로 외부 연결로 선언해놓고 한쪽 모듈에서 그 명칭을 사용하지 않는 것과 다름이 없지 않나 생각되는데요
>
저도 처음엔 명칭의 연결(linkage)이 통용범위(유효범위, scope)와 동일한
방식으로 동작하리라 생각했었습니다. 예를 들어, 프로그램 전체에 foo
라는 명칭이 외부 연결로 사용되더라도 한 모듈이 그 외부 연결 명칭을
참조하지 않는다면 foo 라는 명칭을 다른 목적을 위해 내부 연결로 사용할
수 있다고 생각했었습니다. 즉, 더 작은 scope 에서 더 큰 scope 에 선언
된 명칭을 가려서 다른 목적으로 사용할 수 있는 것과 다르지 않은 방식
이라 생각한 것입니다.
하지만, 프로그램의 시작점인 main() 함수가 정의되어 있는 모듈과 다른
모듈에서 내부 연결로 main 이라는 이름을 사용할 수 있는가에 대한 고민
을 하느라 표준을 살펴보니 실상은 그렇지 않았습니다.
특정 모듈에서 해당 명칭을 실제로 사용하든 그렇지 않든, 프로그램
내에서 일단 어떤 명칭이 외부 연결로 선언된다면, 그 명칭은 프로그램
전체에서 예약되는 것으로 봐야 합니다. 다시 말해, 내부 연결을 갖는
명칭은 단일 파일(정확히는 translation unit) 내에서 유일해야 하며,
외부 연결을 갖는 명칭은 (연결을 "갖는" 명칭을 통틀어) 전체 프로그램
내에서 유일해야 합니다. 이는 내부 연결이든, 외부 연결이든 일단 연결을
"갖는" 명칭을 external declaration/definition 으로 묶어 취급하기
때문에 발생하는 결과입니다.
제가 실제 경험했던 대부분의 환경에서는 말씀하신 것처럼 내부 연결 명칭
이 외부 연결 명칭을 가리며 기대한대로 동작해주지만, 이러한 행동을
표준이 보장해주지 않는 이유가 실제 가장 엄격한 환경을 배려하기 위함
인지, 아니면 논리적 간결성을 위한 것인지는 저도 알지 못합니다. 하지만
C90 이후 단 한번도 이 부분에 대한 문제 제기가 없었던 것을 감안하면,
실제 문제가 될 수 있는 환경의 존재 여부를 떠나 확실히 "잘못된"
프로그램으로 규정하는 것이 지배적 의견이라는 느낌이 듭니다.
> 프로그램 전체에 걸쳐서 사용될 명칭이 그 일부인 어떤 하나의 소스에서 사용되지 않을경우
> 물론 "올바르지는" 않지만 우연히 같은 타입인데다가 꼭 그 명칭을 써야겠다고 생각되면
> 헤더 파일이 인쿨루드 되는 기점 보다 앞서 내부연결로 선언하는것이 연결이 결정되는 규칙에 따라 문제가 없을꺼 같은데요
> (설명해주신 명칭의 의미가 다르거나 매크로에 사용되지 않았다고 가정했을때에)
>
제3자가 제공하는 헤더 파일일 경우 현실적으로 이런 경우가 그리 많지는
않습니다.
> 제가 그렇게 프로그래밍을 하겠다는것이 아니라 표준에 대해서 좀더 알고 싶어서 질문드리는것입니다 흠;
>
> 전 제 질문을 정리하고 글을 쓰는데에도 시간이 꽤나 걸리던데
> 한참 장문인 답변을 써주시는데 정말로 감사하게 생각하고있습니다 T.T
>
제가 좋아서 하는 일인데 감사까지 해주시니 보람도 배로 느낍니다. ^^
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
전웅 교수님!
번역하신 C: A reference manual 잘 읽고 있습니다.
지금 선언 부분까지 왔는데. 내용이 너무 좋네요.
덕분에 지금까지 오는데 일주일 이상 걸렸네요..;
이 문제와 관련해 좀
이 문제와 관련해 좀 미심쩍은 부분이 없지 않아 있어 csc 그룹에 포스팅
해보았습니다.
http://groups.google.co.kr/group/comp.std.c/browse_frm/thread/9b0568b8903c5f1a/
아직 진행중(?)이지만, 의외로 표준의 문제점을 찾은 것일 수도 있습니다. 좀 더
지켜본 후 결과를 정리해 올리도록 하겠습니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
제가 쓸 글: > > 이
제가 쓸 글:
>
> 이 문제와 관련해 좀 미심쩍은 부분이 없지 않아 있어 csc 그룹에 포스팅
> 해보았습니다.
>
> http://groups.google.co.kr/group/comp.std.c/browse_frm/thread/9b0568b890...
>
> 아직 진행중(?)이지만, 의외로 표준의 문제점을 찾은 것일 수도 있습니다. 좀 더
> 지켜본 후 결과를 정리해 올리도록 하겠습니다.
>
요즘 hclc 는 거의 죽었고, csc 역시 예전만큼 활성화되어 있지 않네요.
Eris Sosman 의 해석에 대한 제 반론과 질문에 대해 더 이상 csc 에서
논의가 진행되지 않아, 귀차니즘을 무릅쓰고 지인들에게 메일을 돌려
의견을 구했습니다.
위원회 멤버한테는 답변을 얻지 못해 유권해석이라고는 할 수 없으나 다들
기본적인 "의도"가 내부연결 명칭으로 외부연결 명칭을 가리는 것을 허용
하는 것일 가능성이 크다는 사실에는 동의를 표했습니다.
csc 논의 내용에서도 언급됐듯이, C90 에서도 해당 부분이 동일했던 점을
고려하면, 해당 부분을 최초 작성할 때 내부/외부 연결에 대한 고민이
없었던 것으로 판단됩니다.
이 부분 수정에 대해서는 제가 Defect Report 을 준비할 예정입니다.
(연결을 달리해) main() 함수를 중복 정의하는 문제에 대해 고민한 이후
부터 표준을 있는 그대로 해석해 외부연결 명칭이 보이지 않는 파일에서도
동일한 내부연결 명칭을 정의할 수 없다고 판단했었으나 의도는 표준 해석
과 다른다는 점을 확인하게 되었습니다. 따라서 많은(?) 분들이 의구심을
품었던 아래 코드는 올바른 코드로 보는데 무리가 없어 보입니다.
단, 이는 b.c 에서 a.c 에서 정의한 외부연결 명칭이 아예 보이지 않는
경우에만 해당됩니다. 한 파일에서 하나의 명칭을 두(외부/내부) 연결을
모두 갖도록 선언 하는 것은 여전히 허용되지 않습니다.
표준에 대한 해석이라도 의심이 들면 좀 더 확인한 후에 답변했어야
했는데 너무 성급하게 결론을 내려 답변을 드렸습니다. 반성합니다.
이제 예전에 적었던 글들을 찾아 잘못된 부분을 수정해야겠군요. T.T
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
좀더 이해가 쉽게 바뀌겠군요.
실은 예전에 설명하실때 도저히 이해가 안 갔거든요.
이렇게 복잡하게 이해를 해야하나라고 고개를 절래절래 흔들었었죠.
그런데 고민하셨던 main 은 어떻게 되는거죠?
main 에 대해 고민한
main 에 대해 고민한 적은 없습니다. --;
내부연결을 갖는 명칭으로 main 을 사용하는 경우에 대해 답을 준비하는
과정에서 제가 "알고있던" 내용과 표준의 "글자 그대로의" 해석이 다름을
발견하게 된 것이지요. 물론, 이 논의에서 보여주듯이, 배경에 대한 의심
없이 표준을 지나치게 믿었다가 발등 찍히는 경우를 당하게 된 것입니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
말꼬랑지 잡기 ^_^a
http://kldp.org/node/80188#comment-380485
>>> 프로그램의 시작점인 main() 함수가 정의되어 있는 모듈과 다른 모듈에서
>>> 내부 연결로 main 이라는 이름을 사용할 수 있는가에 대한 고민을 하느라
>>> 표준을 살펴보니 실상은 그렇지 않았습니다.
http://kldp.org/node/80188#comment-382216
>>> (연결을 달리해) main() 함수를 중복 정의하는 문제에 대해 고민한 이후 부터
>>> 표준을 있는 그대로 해석해 외부연결 명칭이 보이지 않는 파일에서도
>>> 동일한 내부연결 명칭을 정의할 수 없다고 판단했었으나 의도는 표준 해석과 다른다는 점을 확인하게 되었습니다.
만나뵌지 오래 되었는데 다시 한번 뵙고 싶군요.
이번에는 C : A Reference Manual 에 서명을 부탁하고 싶다는...^_^
혹시 또 준비하시는 책이 있나요?
>
> http://kldp.org/node/80188#comment-380485
>
> >>> 프로그램의 시작점인 main() 함수가 정의되어 있는 모듈과 다른 모듈에서
> >>> 내부 연결로 main 이라는 이름을 사용할 수 있는가에 대한 고민을 하느라
> >>> 표준을 살펴보니 실상은 그렇지 않았습니다.
>
> http://kldp.org/node/80188#comment-382216
>
> >>> (연결을 달리해) main() 함수를 중복 정의하는 문제에 대해 고민한 이후 부터
> >>> 표준을 있는 그대로 해석해 외부연결 명칭이 보이지 않는 파일에서도
> >>> 동일한 내부연결 명칭을 정의할 수 없다고 판단했었으나 의도는 표준 해석과 다른다는 점을 확인하게 되었습니다.
>
아, 제가 질문을 이해할 때 오해가 있었네요. ㅋㅋ
제가 main 에 대해 고민한 적이 없다고 드린 말씀은 main 이라는 명칭과
관련된 문제를 한번도 생각해 본 적이 없다는 뜻이 아니라 (설마 제가 바로
위에 적어놓고 아니라고 답할리가 --;), 이미 오래 전에 결론지은 문제라
"이 thread 가 진행되는 동안" 따로 고민해 본 적이 (혹은 그럴 필요가)
없다는 뜻이었습니다. 이 thread 에서 다루는 문제가 보다 superset 으로
이 thread 에서 결론이 명칭 main 과 관련된 문제를 지배하게 됩니다.
> 만나뵌지 오래 되었는데 다시 한번 뵙고 싶군요.
> 이번에는 C : A Reference Manual 에 서명을 부탁하고 싶다는...^_^
>
네, 제가 대학원 가기 한참 전이었으니 정말 오래 되었네요. 비싸지도 않은
서명(^^) 나중에 기회가 되면 필히 해드리겠습니다.
> 혹시 또 준비하시는 책이 있나요?
>
요즘은 회사일과 최소한의 휴식을 취하는 것만으로도 하루가 벅차네요.
여러가지 생각이 많지만, 그저 생각만 많은 상태라 안타깝습니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
가령,
가령, 표준라이브러리의 printf를 똑같은 명칭으로 재정의하거나 그 안에서 표준 printf를 명시적 호출해 쓸수 있는 것은 불가능하며,
해답은 myprintf라는 거죠?
제 이해가 맞다면
경우에 따라서 가능하지 않을까요?
내부연결로 그 명칭을 먼저 선언하면 되는데
그럴려면 의미(type)가 같아야하고 또 헤더파일내 그 명칭에 대한 매크로의 존재로 문제를 일으키지 않아야하구요
표준라이브러리든 3자 제공에 의한 비표준라이브러리든 그것과는 상관이 없을꺼 같네요
전웅님께서
>내부 연결을 갖는
>명칭은 단일 파일(정확히는 translation unit) 내에서 유일해야 하며,
>외부 연결을 갖는 명칭은 (연결을 "갖는" 명칭을 통틀어) 전체 프로그램
>내에서 유일해야 합니다. 이는 내부 연결이든, 외부 연결이든 일단 연결을
>"갖는" 명칭을 external declaration/definition 으로 묶어 취급하기
>때문에 발생하는 결과입니다.
>
전웅님게서 이에 대해서 다시 설명해주신것이
외부연결을 갖는 명칭이 프로그램 전체에 걸쳐서 유일하지 않아도 된다는것이죠?
내부연결의 본래 의도가 링커에서 까지 명칭을 알려주지 않는다는것과 함께
외부연결에서부터 명칭을 가려서 내부연결로써 그 명칭을 다른 용도로 사용할수있게요
하지만, 이게 표준의 문제점일수 있다는것이죠? 아래와(main함수) 다르다는것때문에..
그리고 main함수를 잠깐 언급하셔서 저도 생각을 하게 되었는데요
main함수에 대해서만은 이런 규칙들(연결)과는 다르게 프로그램 전체에 대해서 유일해야한다는것인가요?
그러니까 main함수를 프로그램전체중 일부인 다른소스 파일에서 내부연결로 사용하는것에 대해서 어떻게 되는지 궁금증이 생겼는데요
어째 질문이 같은 질문이 되었네요;
> > 가령,
> > 가령, 표준라이브러리의 printf를 똑같은 명칭으로 재정의하거나 그 안에서 표준 printf를 명시적 호출해 쓸수 있는 것은 불가능하며,
> > 해답은 myprintf라는 거죠?
> >
표준 라이브러리에서 예약하고 있는 명칭의 경우 일반적으로 명칭에 적용
되는 규칙 이외에 독특한 규칙이 추가로 적용될 수도 있습니다 - 표준의
라이브러리 도입부에 표준에서 예약하고 있는 명칭에 대한 별도의 규칙이
기술되어 있습니다.
위에서 논의된 바처럼 경우에 따라 <stdio.h> 를 첨가하지 않고 printf
라는 명칭을 내부 연결 명칭으로 사용하는 것이 가능은 합니다, 하지만
목적이 분명치 않은 이상 가독성 측면에서 상당히 좋지 않은 구조입니다.
>
> 제 이해가 맞다면 경우에 따라서 가능하지 않을까요?
> 내부연결로 그 명칭을 먼저 선언하면 되는데
예를 들어, printf 를 선언해주는 <stdio.h> 를 첨가하지 않는 다면
내부연결로 "먼저" 선언하고 말고의 문제가 없습니다 - 즉, 내부연결과
외부연결 선언의 순서 문제 자체가 발생하지 않습니다.
하지만 만약 <stdio.h> 를 첨가하고 그 이전에 printf 라는 명칭을 내부
연결로 선언한다면 무조건 잘못된 코드가 됩니다.
> 그럴려면 의미(type)가 같아야하고 또 헤더파일내 그 명칭에 대한 매크로의 존재로 문제를 일으키지 않아야하구요
> 표준라이브러리든 3자 제공에 의한 비표준라이브러리든 그것과는 상관이 없을꺼 같네요
>
<stdio.h> 는 표준 요구에 의해 항상 printf 를 외부 연결로 선언하게
됩니다.
어떠한 경우에도 표준 라이브러리가 사용하고 있는 또한, 앞으로 사용할
가능성이 있어 예약해 놓은 명칭은 그 어떤 목적으로든 다른 용도로 아예
사용하지 않는 것이 좋습니다.
"벌레"는 으슥한 곳에서 나오기 마련입니다.
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
저기... main 은?
물론 좋은 방식이 아니라는 것은 알고 있습니다만 궁금해서... ^_^a
아! 그렇군요
표준 라이브러리에 사용된 명칭에 대해서 별도의 규칙이 있는줄은 몰랐네요
단순히 '표준'이라는 꼬리표를 달고나오니 이식성이 있게 만들어져 그것을 보장하고
그 이외엔 다른 라이브러리와 다르지 않겠구나 정도로 생각해두고 있었거든요
그럼 같은 이야기로 대상이 표준 라이브러리가 아니라면 가능한것인가요?;;라고 말하면 또 다른 안되는 이유가 있으려나요 흠;;
실은, 이 질문이 처음 본문의 내용인데
외부연결 의미로 사용되는 extern 기억부류자가(중의적으로) 특이하게도 이전 선언의 연결을 물려받는 기능때문에
생각해본것이 이거거든요
이를 이용해서 표준라이브러리에 대해서 명칭을 가려 사용하지 못한다면
(다른 3자 제공에 의한 비표준 라이브러리는 어떻죠?)
아마, 다른 특별한 상황에 대한 유용성 때문에 그리되도록 했을꺼 같은데
그렇지 않다면 그런 복잡해보이는 연결규칙이 무슨소용이 있나 생각도 들구요;
> >내부 연결을 갖는 >
> >내부 연결을 갖는
> >명칭은 단일 파일(정확히는 translation unit) 내에서 유일해야 하며,
> >외부 연결을 갖는 명칭은 (연결을 "갖는" 명칭을 통틀어) 전체 프로그램
> >내에서 유일해야 합니다. 이는 내부 연결이든, 외부 연결이든 일단 연결을
> >"갖는" 명칭을 external declaration/definition 으로 묶어 취급하기
> >때문에 발생하는 결과입니다.
> >
>
> 전웅님게서 이에 대해서 다시 설명해주신것이
> 외부연결을 갖는 명칭이 프로그램 전체에 걸쳐서 유일하지 않아도 된다는것이죠?
다소 오해의 여지가 있는 표현입니다. "외부"연결을 갖는 명칭이 서로 다른
개체를 위해 사용되면서 한 프로그램 안에서 출현하는 것은 허용되지
않습니다. 단, 아래 설명하듯이 내부연결을 갖는 명칭으로 외부연결 명칭을
숨기는 것은 가능하다는 것이 표준의 "의도된" 해석이라는 것이 이번 논의
의 결론입니다.
> 내부연결의 본래 의도가 링커에서 까지 명칭을 알려주지 않는다는것과 함께
> 외부연결에서부터 명칭을 가려서 내부연결로써 그 명칭을 다른 용도로 사용할수있게요
>
단, 내부연결 명칭을 선언해 사용하는 파일 안에서는 해당 내부연결 명칭이
가리는 외부연결 명칭을 참조할 수 있는 방법이 없습니다.
> 하지만, 이게 표준의 문제점일수 있다는것이죠? 아래와(main함수) 다르다는것때문에..
>
"아래와(main함수) 다르다는 것"이 무엇을 의미하는지 모르겠지만, 표준의
문제점이라는 이야기는 현재 표준의 해석을 있는 그대로, 글자 그대로
따르면 내부연결 명칭으로 외부연결 명칭을 가리는 것 자체를 금지하고
있다는 것입니다. 처음엔 이것이 (어떤 매우 엄격한 환경을 고려해) 의도된
해석이라고 생각했으나, 논의 결과 위원회의 의도는 표준의 "문자
그대로의" 해석과는 다를 수 있다는 것입니다. 따라서 표준의 수정이
필요한 부분 중 하나로 보고 있습니다.
> 그리고 main함수를 잠깐 언급하셔서 저도 생각을 하게 되었는데요
> main함수에 대해서만은 이런 규칙들(연결)과는 다르게 프로그램 전체에 대해서 유일해야한다는것인가요?
>
특별히 main 함수의 "명칭"에 대해 따로 규정하는 부분은 없습니다. 따라서
일반 명칭과 동일한 제약이 주어진다고 보시면 됩니다.
> 그러니까 main함수를 프로그램전체중 일부인 다른소스 파일에서 내부연결로 사용하는것에 대해서 어떻게 되는지 궁금증이 생겼는데요
>
> /* a.c */
> int main()
> {
> ...
>
> /* b.c */
> static int main()
> {
> ...
>
문제가 없다는 것이 표준의 "의도된" 해석이라는 것이 결론입니다. 단,
b.c 에서 "직접" (a.c 의 다른 함수를 통해 간접적으로 호출하는 것은 물론
가능합니다) a.c 의 외부연결 명칭을 갖는 함수 main 에 접근할 수 있는
방법은 없습니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
> 표준 라이브러리에
> 표준 라이브러리에 사용된 명칭에 대해서 별도의 규칙이 있는줄은 몰랐네요
> 단순히 '표준'이라는 꼬리표를 달고나오니 이식성이 있게 만들어져 그것을 보장하고
> 그 이외엔 다른 라이브러리와 다르지 않겠구나 정도로 생각해두고 있었거든요
> 그럼 같은 이야기로 대상이 표준 라이브러리가 아니라면 가능한것인가요?;;라고 말하면 또 다른 안되는 이유가 있으려나요 흠;;
>
표준 라이브러리가 아닌데 어떻게 표준이 무언가를 요구하거나 강요할 수
있을까요? ;-) 기본적으로 C 언어로 구현된 것이라면 기본적인 사항에
대해서는 표준의 일반적인 내용이 적용되겠지만, 해당 라이브러리가 어떤
다른 표준 (예를 들면, POSIX) 을 따르는 것이라면 해당 표준의 제약을
받게 될 것이고, 어떤 다른 기준 (해당 라이브러리에 대한 문서) 에 의해
제약을 받을 수도 있는 등 다양한 경우가 있을 수 있습니다.
> 실은, 이 질문이 처음 본문의 내용인데
> 외부연결 의미로 사용되는 extern 기억부류자가(중의적으로) 특이하게도 이전 선언의 연결을 물려받는 기능때문에
> 생각해본것이 이거거든요
>
그럴때 사용하기 위해서 넣은 규칙이 아닙니다! 그와 같은 구조는 "매우
매우" 위험한 편법입니다. 실제 코드에 사용하지 마시기 바랍니다.
> 이를 이용해서 표준라이브러리에 대해서 명칭을 가려 사용하지 못한다면
> (다른 3자 제공에 의한 비표준 라이브러리는 어떻죠?)
> 아마, 다른 특별한 상황에 대한 유용성 때문에 그리되도록 했을꺼 같은데
> 그렇지 않다면 그런 복잡해보이는 연결규칙이 무슨소용이 있나 생각도 들구요;
>
흠... 이와 관련된 질문이 애초에 제 책을 보시다가 나온 것으로 기억하고
있습니다. 제 기억으론 제 책에서 그와 같은 복잡한 연결 결정 규칙을 정의
한 이유를 설명하고 있습니다. 근본적인 이유는 one-pass compiler 를
고려해 "첫번째" 선언을 통해 연결을 확정지을 수 있도록 하기 위해서
입니다. 보다 기술적인 내용은 책을 참고하시기 바랍니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
main 역시 문제가 없다면...
그렇다면 program 의 진입점은 main 이라는 이름의 함수만으로 결정되는 것이 아니라
linker 가 알 수 있는 외부연결명칭의 main 이라는 거군요.
그렇다면 내부연결을 갖는 main 이 어떤 type 이어도 상관없겠네요?
> 그렇다면 program 의
> 그렇다면 program 의 진입점은 main 이라는 이름의 함수만으로 결정되는 것이 아니라
> linker 가 알 수 있는 외부연결명칭의 main 이라는 거군요.
>
넵, 표준도 외부연결의 main 함수가 hosted implementation 에서 프로그램
의 시작점임을 분명히(?) 하고 있습니다.
> 그렇다면 내부연결을 갖는 main 이 어떤 type 이어도 상관없겠네요?
>
함수가 아니어도 상관없습니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
감사합니다 ㅜ.ㅜ
이제 궁금증이 다 풀린거 같네요
아! 그 내용을 책에서 읽었었는데
이후 연결이 있는 다른 선언을 잘못된것으로 하지 않고 물려받게 한것이...(그래서 복잡해진)
이를 잘 활용하라는 의도정도로 생각했거든요
글이 꽤나 길어졌는데 아니라니 허탈하기도 하고 T.T
다시한번 감사드립니다 (__) 도움이 많이 되었네요!
댓글 달기