extern 은 옵션이다???

freezm7의 이미지

== main.c

int share;
void share20();

int main(int arg, char** argv)
{
    share = 10;
    printf("%d\n", share);

    share20();  
    printf("%d\n" share);
}


== sub.c

int share;

void share20()
{
     share = 20;
}

==

gcc main.c sub.c

하면 상식(제가 알고 있는한)
링크 에러가 떠야 할 것 같습니다.

main.o 에도 share 라는 변수가 있고
sub.o 에도 share 라는 변수가 있으니까요.

그런데 아무 문제없이 컴파일이 됩니다.
그리고 결과는

10
20

으로 출력되네요.

어떻게 이런일이???

서지훈의 이미지

int share; ====> extern int share = 0; 전역 변수의 기본값이 위와 같기 때문입니다. 그래서 extern 따로 붙이 필요 없이 잘 되죠.

이 내용은 책 함 보면은 나올긴데...-_-ㅋ

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

정태영의 이미지

int share

double share 여도.. 컴파일되고 실행도 될걸요..
...

다만.. 결과가.. 미묘해지겠지만 =3=33

#include <stdio.h>

int share;

void c_share1(){
	share = 10;
}
void share1(){
	printf("share1: %d\n", share);
}

#include <stdio.h>

double share=1.0;

void c_share1();
void share1();

void c_share2(){
	share = 10;
}

void share2(){
	printf("share2: %lf\n", share );
}

int main( int argc, char** argv ){

	c_share1();
	share1();
	share2();

	c_share2();
	share1();
	share2();

	return 0;
}

정도로 컴파일하고 실행시켜보시면...
..

Quote:
aqua@cafri ~/tmp/link $ ./l
share1: 10
share2: 1.000000
share1: 0
share2: 10.000000

이런 결과가 나옵니다..
...

외부에서 쓸 일 없는 전역변수라면.. static을.. 붙여줘서 이런 일이
발생하지 않도록 해야겠죠 :)

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

freezm7의 이미지

서지훈 wrote:
int share; ====> extern int share = 0;
전역 변수의 기본값이 위와 같기 때문입니다.
그래서 extern 따로 붙이 필요 없이 잘 되죠.

이 내용은 책 함 보면은 나올긴데...-_-ㅋ

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

링크시 이름 충돌이 왜 안 일어나는지에 관한 질문인데, 기본값이 위와 같다는게 무슨 관련이 있는지 모르겠네요.

태영님, 예제까지 만들어 실험해 주셔서 감사합니다.

근데 제 질문은 결과가 궁금한게 아니라,
(저렇게 되는 결과를 보고 제가 질문한 것이죠 ^^;)

과정, 즉, 왜 이름 충돌 없이 링크가 되냐는 것입니다.

조금 더 알려주시면 감사하겠습니다.

즐겁게 살아 볼까나~*

서지훈의 이미지

원래가 extern이라는 키워드가 외부의 변수를 그대로 사용을 하겠다는 의미입니다.
따로 새로 선언을 해줄 필요가 없이.
그렇기 때문에 main.c와 sub.c에서 선언된 int share; 이 변수는 같은 변수 입니다.
초기화선언은 main.c에서 선언 한데로 사용이 되고, sub.c에서 main.c에서 선언된 share 변수를 새로운 선언 없이 사용을 하는 거구요.
지금 변수가 선언이 된게 share 하나 밖에 없으니 충돌이 날려도 날 수가 없죠.
손바닥도 마주쳐야 소리가 나듯...-_-ㅋ

아마도... extern의 의미에 혼동이 있으신듯 하네요^^

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

doldori의 이미지

혼동하시는 분은 서지훈님 같은데요.
원 코드는 one definition rule에 어긋나므로 분명히 잘못된 것입니다.
그리고 코드에 잘못이 있는 이상 그 결과는 undefined입니다.
왜 이런 결과가 나오는지 따지는 것은 무의미하죠.

정태영의 이미지

doldori wrote:
혼동하시는 분은 서지훈님 같은데요.
원 코드는 one definition rule에 어긋나므로 분명히 잘못된 것입니다.
그리고 코드에 잘못이 있는 이상 그 결과는 undefined입니다.
왜 이런 결과가 나오는지 따지는 것은 무의미하죠.

http://bbs.kldp.org/viewtopic.php?t=28535&highlight=extern+static

기본적으로 static 을 붙이지 않으면.. extern 속성을 가지는 걸로 알고 있습니다..

그러나 결과가 undefined는 아닌것 같군요 흐흐흐

http://sal.hongik.ac.kr/~sikim/Courses/2004/sp/lecture/files/linker&loader.ppt
9~11 페이지쯤에서.. weak symbol , strong symbol 등 얘기 등과 관련된 것들을 읽어보시면.. freezm7 님이 원하시는 답은 찾을 수 있으실거 같군요 :)

int share = 1;
식으로 둘 다 strong symbol 이 된다면.. 링크할때 에러가 나겠지만..
아니면.. 위의 자료에 있는 내용에 따라서 :) 링크가 되겠죠..

외부에서 쓸 일 없는 변수들엔 static을 붙이는 습관을 들이세요 흐흐

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

doldori의 이미지

정태영 wrote:
그러나 결과가 undefined는 아닌것 같군요 흐흐흐

http://sal.hongik.ac.kr/~sikim/Courses/2004/sp/lecture/files/linker&loader.ppt
9~11 페이지쯤에서.. weak symbol , strong symbol 등 얘기 등과 관련된 것들을 읽어보시면.. freezm7 님이 원하시는 답은 찾을 수 있으실거 같군요 :)

int share = 1;
식으로 둘 다 strong symbol 이 된다면.. 링크할때 에러가 나겠지만..
아니면.. 위의 자료에 있는 내용에 따라서 :) 링크가 되겠죠..

말씀하신 weak symbol, strong symbol 등은 C 언어에서는 정의되지 않은
개념입니다. hclc에서 이와 비슷한 논의가 있었습니다.

http://groups.google.co.kr/groups?selm=bd0fn2%2412c%241%40news.hananet.net

vajna의 이미지

doldori wrote:
혼동하시는 분은 서지훈님 같은데요.
원 코드는 one definition rule에 어긋나므로 분명히 잘못된 것입니다.
그리고 코드에 잘못이 있는 이상 그 결과는 undefined입니다.
왜 이런 결과가 나오는지 따지는 것은 무의미하죠.

무의미한 짓 한번 해봤습니다.
일단 덤프는

Quote:

Set to 10
share1:10 addr:00408030
share1_retry:1.000000 addr:00408030
share2: 1.000000 addr:00408030
Set to 20
share1:0 addr:00408030
share1_retry:20.000000 addr:00408030
share2: 20.000000 addr:00408030
hold1
hold2 0000000f
hold3 0000007f
hold4 000000ff

코드는 아래와 같습니다.

"main.c"
#include <stdio.h> 
#include "sharevar.h"

double share=1.0; 

void c_share1(); 
void share1(); 

void c_share2(){ 
	printf("Set to 20\n");
   share = 20; 
} 

void share2(){ 
   printf("share2: %lf addr:%08x\n", share, &share ); 
} 

int main( int argc, char** argv ){ 
	unsigned char *pCasted;

   c_share1(); 
   share1(); 
   share2(); 

   c_share2(); 
   share1(); 
   share2(); 

printf("hold1\n");
getch();

	pCasted = (unsigned char *)&share;
	pCasted[3] = 15;

printf("hold2 %08x\n", *(pCasted+3));
getch();

	pCasted[7] = 127;

printf("hold3 %08x\n", *(pCasted+7));
getch();

	pCasted[10646] = 255;

printf("hold4 %08x\n", *(pCasted+10646));
getch();

	return 0; 
} 

"share.c"
#include <stdio.h> 

int share; 
int shareOnShare;

void c_share1(){ 
	printf("Set to 10\n");
   share = 10; 
} 
void share1(){ 
   printf("share1:%d addr:%08x\n", share, &share); 
   printf("\tshare1_retry:%lf addr:%08x\n", *((double *)&share), &share); 
} 

참고로 VC++ 6.0에서 컴파일 했습니다.
힙을쓰는 전역이 정의에 따라 double로 읽을때는 double로 읽히고 int로 읽을때는 int로읽히며, 쓰기에서도 마찬가지이며, 이는 포인트 캐스팅을 통해 값을 접근했을때

Quote:

share1_retry:1.000000 addr:00408030
.....................
share1_retry:20.000000 addr:00408030

이같은 결과로 나오는걸로 볼때 같은 주소에 캐스팅에 의한 값의 접근 결과로 이상한 값이 나온것으로 추측하였고 이를 뒷받침하기 위해 삽질좀 더해봤습니다... :shock:아래와 같이 소스 수정하여 더블형이 표나도록 값을 입력시켜 줘보았습니다.

"share.c"
#include <stdio.h> 

#define FEEDVALUE	0xF2345678

int share; 
int shareOnShare;

void c_share1(){ 
	printf("Set to %08x\n", FEEDVALUE);
   share = FEEDVALUE; 
} 
void share1(){ 
   printf("share1:%d addr:%08x\n", share, &share); 
   printf("\tshare1_retry:%lf addr:%08x\n", *((double *)&share), &share); 
} 

맨티사 부분이라 무지 큰수를 집어넣어야 영향을 줄 수 있었습니다.
된장:cry: 0.000001변하는군요..

Quote:

Set to f2345678
share1:-231451016 addr:00408030
share1_retry:1.000001 addr:00408030
share2: 1.000001 addr:00408030
Set to 20
share1:0 addr:00408030
share1_retry:20.000000 addr:00408030
share2: 20.000000 addr:00408030
.....

머나먼 땅으로 우리 동무가 이제 떠나간다네.
고향의 바람이 불어와 동무 뒤를 따르고
사랑스러운 도시가 푸른 이내 속에서 사라지네.
정든 집, 푸른 동산, 부드러운 눈길도...

GunSmoke의 이미지

doldori 님이 링크하신 뉴스 그룹의 토론 내용을 정리합니다.

http://groups.google.co.kr/groups?selm=bd0fn2%2412c%241%40news.hananet.net

main.c에서 파일 통용범위의 대상체 share는 extern이라는 기억부류 지정자나 초기치가 없기 때문에 완전한 정의가 아닌 tentative definition으로 다루어 집니다. tentative definition은 해당 명칭에 대한 분명한 정의가 없을 경우 translation unit의 마지막, 즉 프로그램의 소스 끝에서 0을 초기치로 갖는 정의로 다루어 집니다.

== main.c

int share;
void share20();

int main(int arg, char** argv)
{
    share = 10;
    printf("%d\n", share);

    share20();  
    printf("%d\n" share);
}

sub.c에서 역시 마찬가지입니다.

== sub.c

int share;

void share20()
{
     share = 20;
}

==

이렇게 보면 두개의 프로그램 소스에 임시정의 int share;가 두번 정의된 것이라고 볼 수 있습니다. 위에서 몇 분이 말씀해 주셨듯이 파일 통용범위에서 선언된 대상체는 외부 연결을 갖는 명칭이기 때문에 프로그램 전체에서 두번 선언된 셈입니다. 본래 C의 외부 정의 모델에 따르면 이러한 프로그램은 잘못된 것입니다.

그러나 유닉스 계열의 임플리멘테이션에서 사용하는 완화된 참조/정의 모델에서는 이와 같은 정의되지 않는 행동을 확장으로 지원하여 쓰이고 있습니다.
(IT 백두대간 C 언어, 전웅, p.914 여기서 잠깐)

大逆戰

서지훈의 이미지

넘 얘기가 또 어려워 지는군요.
넘 어려워서 이해하기 힘들고.
간단히... 원론적인거...
제가 아는 전역 변수는 기본적으로 extern으로 선언이 되고, 0으로 셋팅이 되는 걸로 아는데?
이게 undefined라는 건지?
아님 tentative(시험적인 - 방금 사전에서 뜻 확인)인지?
지금 얘기는 흘러 흘러 가고 있는데...
여러 의견은 나오고 있는데...
얘기의 정확한 근거와 하고자 하는 얘기의 논지는 끝부분에 명확히 하면은 또 좋은 자료가 될듯하네요.

만약 제가 알고 있는게 틀렸다면, 또 기쁘게 한가지를 더 배우게 되는 일^^

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

doldori의 이미지

정의(definition)와 선언(declaration)의 의미를 정확히 알아야 합니다.
정의는 "이러한 함수 또는 개체를 만들라",
선언은 "이러한 함수 또는 개체가 어딘가에 있으니 참고하라"고
컴파일러에게 알려주는 것입니다.
그리고 선언은 여러 번 해도 되지만 정의는 단 한 번만 할 수 있습니다.
원 코드에서 share는 두 번 정의했으므로 이 규칙을 위반한 것이며,
이 경우 implementation은 마음대로 할 수 있습니다. 링크 에러를 낼 수도
있고 아무 문제가 없는 것처럼 보일 수도 있습니다.
원 코드를 맞게 고치면

// main.c
extern int share; // 선언. 보통 이 문장은 헤더에 넣어 #include 함
...

// sub.c
int share; // 정의
...

정도가 되겠죠.

서지훈의 이미지

doldori wrote:
정의(definition)와 선언(declaration)의 의미를 정확히 알아야 합니다.
정의는 "이러한 함수 또는 개체를 만들라",
선언은 "이러한 함수 또는 개체가 어딘가에 있으니 참고하라"고
컴파일러에게 알려주는 것입니다.
그리고 선언은 여러 번 해도 되지만 정의는 단 한 번만 할 수 있습니다.
원 코드에서 share는 두 번 정의했으므로 이 규칙을 위반한 것이며,
이 경우 implementation은 마음대로 할 수 있습니다. 링크 에러를 낼 수도
있고 아무 문제가 없는 것처럼 보일 수도 있습니다.
원 코드를 맞게 고치면

// main.c
extern int share; // 선언. 보통 이 문장은 헤더에 넣어 #include 함
...

// sub.c
int share; // 정의
...

정도가 되겠죠.


// main.c
int share = 0; // 선언. 보통 이 문장은 헤더에 넣어 #include 함
...

// sub.c
extern int share; // 정의
...

이게 맞는 표현 같은데요...-_-ㅋ

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

sliver의 이미지

서지훈 wrote:
doldori wrote:
정의(definition)와 선언(declaration)의 의미를 정확히 알아야 합니다.
정의는 "이러한 함수 또는 개체를 만들라",
선언은 "이러한 함수 또는 개체가 어딘가에 있으니 참고하라"고
컴파일러에게 알려주는 것입니다.
그리고 선언은 여러 번 해도 되지만 정의는 단 한 번만 할 수 있습니다.
원 코드에서 share는 두 번 정의했으므로 이 규칙을 위반한 것이며,
이 경우 implementation은 마음대로 할 수 있습니다. 링크 에러를 낼 수도
있고 아무 문제가 없는 것처럼 보일 수도 있습니다.
원 코드를 맞게 고치면

// main.c
extern int share; // 선언. 보통 이 문장은 헤더에 넣어 #include 함
...

// sub.c
int share; // 정의
...

정도가 되겠죠.


// main.c
int share = 0; // 선언. 보통 이 문장은 헤더에 넣어 #include 함
...

// sub.c
extern int share; // 정의
...

이게 맞는 표현 같은데요...-_-ㅋ

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

doldori님이 맞습니다.

TCPL같은 책 해당부분 찾아서 읽어보심이 좋을듯 합니다.

GunSmoke의 이미지

freezm7 wrote:

gcc main.c sub.c

하면 상식(제가 알고 있는한)
링크 에러가 떠야 할 것 같습니다.

main.o 에도 share 라는 변수가 있고
sub.o 에도 share 라는 변수가 있으니까요.

그런데 아무 문제없이 컴파일이 됩니다.
그리고 결과는

10
20

으로 출력되네요.

어떻게 이런일이???

(다시한번 말씀드리지만) 그렇게 원칙을 위반한 코드임에도 불구하고 유닉스 환경의 임플리멘테이션에서는 이것을 확장으로 인정해 왔다는 것입니다. 그래서 OP는 아무 문제 없이 컴파일되었다는 점을 물어본 거구요.

'TCPL' 이게 무슨 책인지 잘 모릅니다만 (K&R2인가요? The C Programming Language?? 맞는거 같은데) 한빛미디어에서 출판된 전웅님이 쓰신 'IT 백두대간 C 언어 펀더멘탈'을 이용해서 공부하시길 권하는 바입니다.
'13장 외부 정의 모델'에 해당 내용이 자세히 설명되어 있습니다.

大逆戰

최종호의 이미지

GunSmoke wrote:
freezm7 wrote:

gcc main.c sub.c

하면 상식(제가 알고 있는한)
링크 에러가 떠야 할 것 같습니다.

main.o 에도 share 라는 변수가 있고
sub.o 에도 share 라는 변수가 있으니까요.

그런데 아무 문제없이 컴파일이 됩니다.
그리고 결과는

10
20

으로 출력되네요.

어떻게 이런일이???

(다시한번 말씀드리지만) 그렇게 원칙을 위반한 코드임에도 불구하고 유닉스 환경의 임플리멘테이션에서는 이것을 확장으로 인정해 왔다는 것입니다. 그래서 OP는 아무 문제 없이 컴파일되었다는 점을 물어본 거구요.

'TCPL' 이게 무슨 책인지 잘 모릅니다만 (K&R2인가요? The C Programming Language?? 맞는거 같은데) 한빛미디어에서 출판된 전웅님이 쓰신 'IT 백두대간 C 언어 펀더멘탈'을 이용해서 공부하시길 권하는 바입니다.
'13장 외부 정의 모델'에 해당 내용이 자세히 설명되어 있습니다.

논외입니다만, 전웅님책이 현재 품절 상태이고,
출판사에서 더 찍을지 말지 고민하고 있는 상태라고 합니다.
관심있으신 분들 한번씩 전화날려주시기 바랍니다.

The C Programming Language 를 무슨 책인지 잘 모른다고 하시며
변두리 책 취급하시면 많은 분들이 섭해하지 않으실까요? 8)

GunSmoke의 이미지

최종호 wrote:

The C Programming Language 를 무슨 책인지 잘 모른다고 하시며
변두리 책 취급하시면 많은 분들이 섭해하지 않으실까요? 8)

오해이십니다.
K&R2를 white book이라고 부르는 경우는 자주 봤지만 TCPL이라고 들어본 적이 없기 때문에 그런 말을 남긴겁니다.

大逆戰

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.