본문 바로가기
Engineering/C/C++

[펌]변수의 선언과 할당

by 알 수 없는 사용자 2008. 7. 11.

모든 자료형(변수)의 선언 구조는 (기억클래스)  ->  (형수식자)  ->  (자료형)  ->  (변수리스트;) 의 순서로 이루어집니다. auto(기억클래스) volatile(성질 형수식자) int(integer 자료형) A(변수명) 이지요. 그런데 이렇게 복잡하게 안쓰고 int A; 라고 해도 가능한 이유는 기억클래스나 형수식자는 생략이 가능하기 때문입니다.

“생략 가능한데 뭐하라 만들었냐~” 라고 생각하시는 분을 위하여 뒷부분에 자세하게 설명드리겠으며 이게 이 글의 핵심~! 입니다. 여기쯤 읽다가 “시방 지금 뭔 말이여~! (ㅡㅡ+)” 하며 창을 닫으시려는 분이 있을까봐. 이쯤에서 우선 (기억클래스), (형수식자)에 대하여 간략하게 설명을 드리겠습니다.

  • 기억 클래스 : static, auto, extern, register
  • 형수식자 : 설질수식자, 부호수식자, 크기수식자
  • 성질 수식자 : const, volatile
  • 부호 수식자 : signed, unsigned
  • 크기 수식자 :  short, long

자료형의 선언은 이러한 클래스 및 수식자의 기술에 의해 어떠한 특성을 부여합니다.

기억 클래스 : static, auto, extern, register

static

  1. 블록 내부에서 사용될때 : 블록에서 선언된 변수가 그 값을 유지(함수안에서의 변수값 유지,다시 블록에 들어가도 이전값 유지)
  2. 블록 외부에서 사용될때 : 외부 정적 변수로 함수와 함수 사이에서의 값 유지 하며 유효범위의 제한 (다른 C파일과 그변수 이전에 선언된 함수에서는 접근할 수 없다)의 공개성을 지닌다.
  3. 변수 선언에서 사용될때 : Class의 protected 처럼 다른 C 파일에서는 접근할 수 없도록 제한하는 기능을 한다.

auto : stack에 잠시 생성되는 자동변수(기억 클래스 정의가 생략되면 전부 auto로 인식

extern : 외부 C 파일의 함수에서 접근이 가능하도록 선언(Linker 가 Link할 수 있도록), 선언된 extern 변수는 함수가 소멸해도 메모리에 남아있으며 모든 함수의 전역변수가 된다.

Register : 변수를 register 안에 저장(빠른 access) 3개까지 가능하며 3개를 초과하면 auto로 선언된다. (여기서 3개까지라는건 CPU마다 다르다)

형수식자 : 성질수직자, 부호식자, 크기수식자

성질 수식자
const : 값을 변경하지 않는 변수를 지정
volatile : 일반적으로 H/W등에서 지속적, 비동기적으로 변경되는 값을 정의 할때 사용되며 선언시 컴파일시 최적화를 수행하지 않는다. (H/W Register를 Memory로 Mapping 하면 둘사이의 불일치 시간이 발생한다.) (컴파일러는 컴파일시 중복된 read나 write등을 제거한다. 하지만 volatile 변수는 프로그래머에 의한 임의의 중복(비동기적으로 변하기 때문에 계속 읽어야한다) 임으로 최적화시 의도한 목적을 달성할 수 없다. 사용하기전에 반드시 한번 읽으라는(비동기적으로 변경됨으로) 의미로 이해하면 쉽겠다~


부호 수식자
signed : - + 포함
unsigned : +만

크기 수식자
short : 보통 2byte
long : 보통 4byte

이제 아셨지요? 여기서 가장 중요한건 (기억 클래스)입니다. 거창하게 Storage Class라고 하지요.. Storage Class는 결국 저 변수를 어디다 저장할거냐를 정해주는 거지요.

C 언어는 메모리를 요로코롬 3개(stack, bss, data)로 나눠 쓰지요~ 여기다 하나더~ register는 메모리가 아니고 CPU에 달려있는놈이니 따로 치기로 합시다. 결론부터 말하자면
 

사용자 삽입 이미지

결국 extern = data section, auto = stack section, static = data section, register = register(모자라면 auto)

이런 말이지요~ 그럼 왜 이렇게 저장하는 위치를 정의할수 있게 하였을까요? 그건 위에서 설명드린 특성과 밀접한 관련이 있습니다. Extern은 다른 C파일에서 접근 가능하도록 하여야 하는데 stack에 넣으면 함수종료후 홀라당 사라지기 때문에 data section에 저장되어야 합니다. Auto는 잠시 함수에서 사용할 임시 변수이기 때문에 Stack에 저장하지요~ 변수 중복참조(여러 C파일에서 혹시나 같은 이름의 변수를 사용할지 모르기 때문에)를 방지하기 위한컴퍼일러의 눈물겨운 노력입니다.

Static은 목적이 분명하지요~역시 유지되어야 함으로 Data Section에 저장되며 일반적으로 변수를 함수외부에 선언(global)하면 자동적으로 static 변수가 됩니다. Global 변수를 다른 C파일에서 사용하고 싶으면 extern으로 선언해야 하지요.

여기서 잠깐 extern의 기능을 설명하자면 linker가 object들을 묶을때의 지시자로서 동작합니다. Extern이나 Static이나 Data Section에 저장되기는 마찬가지지만 Linker가 Object를 묶어서 하나의 이미지로 만들 때 다른object에서 찾아서 Link할거냐 아니냐를 정해주는거지요.

static은 함수내부에도 쓰일수 있는데 Global static과 동일하게 값이 유지되지만 다른 함수에서의 참조는 불가 합니다.. 보통 함수내부의 counter를 구현할 때 쓰거나 rand()함수에서도 쓰더군요~ ^^

여기까지도 다 아는 내용이라구요? 그렇다면 여기서 Quiz~!

static int Function(double A, char*B);

같은 함수앞의 static은 무얼까요? 내가 바본줄 알아? “함수의 return값이 static int 이다.” \

라고 말하신다면 “땡~!” 틀렸습니다. 함수를 생성하면 3개의 영역이 할당됩니다. 함수의 동작 코드주소의 포인터 + 인자값 + return값 이지요. 인자값과 return값은 함수를 호출한 함수의 stack에 생성되며 코드야 Text혹은 Code Section에 원래 있는거니까. 포인터만 받아오겠져?

답을 말씀드리자면 선언한 함수의 Type은 return 값에만 적용이 됩니다.  앞의 static은 함수의 포인터에만 적용이 됩니다~ 뭔말이냐하면 static으로 선언한 함수는 해당 C파일 내에서만 호출이 가능합니다~

“그럼 static이 있으니 extern 기억클래스의 함수도 있겠군요?” (@_@)? 라는 질문을 하신다면 탁월한 선택~ 함수는 선언당시 static을 붙이지 않으면 전부 extern입니다. 그래서 A.c에서 선언된 A();함수를 B.c에서 아무 불편없이 사용할수 있는거지요.

자~! 정리합시다. 변수나 함수를 선언할 때 흔하게 빼먹는 (기억클래스)와 (형수식자)는 생략이 가능합니다만. 여기서 중요한건~! 생략이 가능하단 말은 사용자가 정의하지 않으면 자동적으로 선언이 되는거지 기억클래스나 형수식자가 없는건 아니라는 사실입니다.

그래서 변수는 디폴트 값이 함수 안에서는 auto, 함수 밖에서는 static.
함수는 디폴트가 extern 입니다

결국 함수나 변수의 선언은 어디에 어떤 사이즈로 저장하며 다른곳에서의 참조를 허락할것인가를 정해주는 것이라 할 수 있습니다.