cCcode

C Language [핵심정리] - Last 본문

C Language Basic

C Language [핵심정리] - Last

cCcode 2021. 8. 5. 17:04

1. 전역 변수 사용하기

지금까지는 함수 안에서 선언하는 지역변수선언했습니다. 제가 지역변수는 선언한 해당 함수 내에서만 사용할 수 있다고 언급 했었죠. (함수의 범위는 중괄호 시작부터 끝까지 입니다.)  그에 반해 전역변수는 프로그램 전체에서 공유하는 값으로 모든 범위 즉, 모든 함수에서 사용할 수 있습니다. 

선언되지 않은 식별자

이처럼 변수가 선언되지 않은 외부 블록에서는 변수를 사용할 수 없습니다. 이처럼 변수가 사용되는 범위(Scope)가 정해져있기 때문에 주의해야합니다.

외부에서 선언 내부에서 사용
결과

다만, 이처럼 넓은 범위에 선언을 했다면 좁은 범위에서 사용가능합니다.

 

전역 변수는 함수 바깥에 선언합니다. 

전역 변수 선언
결과

+ 전역 변수초기값은 (초기화 하지 않을 경우) 0으로 초기화 됩니다. 이게 초기화 해주지 않으면 쓰레기 값이 들어가는 지역변수와의 차이점 중 하나입니다. 함수에 매개변수로 값을 수정하는 것보다 편해서 자주 사용할 수 도 있습니다만, 그럴 경우 사용되는 함수가 늘어났을 때 어떤 함수에 해당 값을 수정하는 지 알기 어렵습니다. 그리고 지역변수전역변수 명이 의도치 않게 중복될 수 있기 때문에 예기치 않은 결과가 나올 수 있습니다. (지역변수와 전역변수 명이 중복될 경우 해당 블록 변수를 우선시 합니다.)

지역변수와 전역변수가 중복될 경우
결과

소스 파일이 여러 개로 분리되어 있을 경우 전역변수를 사용하는 방법입니다. 일단 사용하려는 변수가 전역변수선언되어 있어야 하고 해당 변수를 사용할 때는 extern 키워드를 사용합니다. (다만, 이때 이미 선언된 전역변수를 가져오지만, 해당 변수의 자료형을 명시해줘야 합니다. 그러니까 전역변수가 선언된 파일에서는 몰라도 선언되어 있지 않은 파일에서는 그 변수를 처음 쓰는거니, 그 변수에 대한 정보명시한다고 생각하면 됩니다.)

extern 키워드
외부에 전역변수를 선언하는 파일(.c)
외부전역 변수를  사용하는 소스파일(.c)

이처럼 다른 소스파일에 선언된 전역변수범위프로그램 범위입니다. 이 때 전역 변수를 선언하는 소스파일에서는 main 함수를 사용하면 안됩니다. (main 함수가 두 소스파일에서 동시에 존재할 때 [ fatal error LNK1169: 여러 번 정의된 기호가 있습니다 ] 라는 에러가 뜹니다.)

 

extern 키워드로는 전역 변수 뿐만 아니라 함수도 외부에서 가져올 수 있습니다.

extern 키워드로 함수 가져오기
함수를 선언한 소스파일(.c)
외부 함수를 사용하는 소스파일(.c)
결과

 

전역 변수를 사용하려면 그 변수를 사용하는 함수보다 먼저 선언되어야 합니다. 만약 함수 이후에 선언된다면 함수에서 해당 변수를 찾지 못해 컴파일 에러가 발생합니다. (C언어는 절차지향이므로)

함수보다 나중에 선언된 경우

[ error C2065: 'string': 선언되지 않은 식별자입니다. ] 라는 에러가 발생합니다. 이 경우에는 extern 키워드로 해당 변수가 선언되었음을 미리 알려주면 됩니다. 그러니까 그전에 배우셨던 전방선언과 비슷한 역할을 해요.

extern 키워드로 전방 선언
결과

다만, 이는 일반적으로 전역 변수선언하는 것보다 불편하므로 선호되는 방법은 아닙니다.

 

2. 기억부류 지정자 사용하기

C언어에서 변수기억 부류 지정자(storage class specifier)를 사용하여 다양한 특성을 지정할 수 있습니다.

기억 부류 지정자

저장장소 부분이 헷갈릴 수도 있는데, 조금 설명을 덧붙이자면 전역 변수(extern)정적변수(static)을 선언할 때 값을 초기화 하지 않으면 BSS부문(.bss)에 생성되며 초기값은 0 입니다. 만약 특정 값으로 초기화 된다면 그 부분은 데이터부문(.data)생성됩니다.

 

자동(auto)변수는 선언할 때 auto 키워드를 붙입니다. 단 전역변수에는 auto를 사용할 수 없습니다.

자동 변수
자동 변수 사용하기
결과

저희가 지금까지 사용한 변수들 그러니까 앞에 기억부류지정자를 따로 지정하지 않은 변수들은 모두 자동 변수(automatic variable)형태를 가지고 있었습니다. 다만 이처럼 저희가 자주 사용하다보니 생략하는 형태로 가게 된것이 아닐까 조심스레 예측해봅니다.

자동 변수의 범위
결과

이처럼 변수가 범위를 벗어나 사라지지 않게 만들기 위해서는 정적변수를 사용해야 합니다. 정적변수는 앞에 static 키워드를 붙입니다. 

정적 변수
정적 변수 사용
결과

num은 정적 변수(함수 블록을 벗어나도 사라지지 않기 때문에)이자 지역 변수(함수 블록 안에서만 접근 할 수 있기 때문)입니다. 만약 전역 변수정적 변수로 만든다면 어떻게 될까요? 

정적 전역 변수를 선언한 소스파일(.c)
정적 전역 변수를 사용할 소스파일(.c)
컴파일 에러

static으로 선언한 변수를 extern으로 사용하면 컴파일(링크)에러가 발생합니다. 즉, 정적 전역 변수는 변수가 선언된 소스파일에서만 사용할 수 있고, 외부에서 가져올 수는 없습니다. (= 전역 변수static 키워드를 사용하면 변수의 범위제한 됩니다.)

정적 전역 변수 사용 (같은 파일에서)
결과

정적 전역변수를 선언한 파일에서 사용하면 위와 같습니다. 다만, 전처럼 extern 키워드를 사용하는 건 불가능합니다. (2개 이상의 기억부류 지정자를 한 변수에 사용할 수 없기 때문에)

 

정적 변수를 초기화 하지 않으면
결과

정적 변수는 위 표를 보시면 알수 있듯이 초기값을 지정해 초기화 해주지 않는다면, 0 이라는 값이 들어갑니다. (+ 정적 변수함수의 매개변수로 주더라도 그 매개변수정적 변수가 되지는 않습니다.)

함수의 매개변수로 정적변수를 준 경우
결과

이처럼 함수의 매개변수정적변수가 되지 않으면서 이 유지되지 않는 모습을 볼 수 있습니다.

 

그리고 정적 함수라는 게 존재하는 데, 정적 함수를 알아보기전 다음 2 개의 소스파일을 확인해보시죠.

소스파일 - 1
소스파일 - 2

이처럼 파일 간의 함수명이 겹치는 경우에는 

컴파일(링크) 에러

이와 같은 링크 에러가 발생하게 됩니다. 즉, 한 프로젝트 안에서는 함수명중복될 수 없습니다. 이 때 main 함수를 포함하고 있는 파일의 함수static 형태로 정의하게 되면

정적 함수
결과

한  파일에 동일한 함수명이 존재하더라도 에러 없이 실행됩니다. 즉 정적 함수를 사용하면 같은 명의 함수를 파일마다 생성할 수 있습니다. 따라서 정적 함수는 기능이 여러 파일로 분리 되어있는 경우 각 파일 안에서만 사용하는 기능을 구현할 때 사용합니다. 

 

변수를 선언할 때 register 키워드를 사용하면 변수는 메모리 대신 CPU 레지스터를 사용합니다. 따라서 일반 변수보단 속도가 빠른 편에 속하죠. 단, 레지스터의 개수 제한적이므로, register 키워드를 사용한다 하여도 모두 레지스터를 사용하지는 않습니다.

레지스터 변수
레지스터 변수의 사용
결과

레지스터 변수는 변수가 CPU 레지스터만 사용합니다. (메모리는 사용하지 않아요) 그래서 &(주소 연산자)메모리 주소를 구할 수 없습니다. 단, 레지스터 변수메모리 주소를 저장할 수는 있기 때문에 역참조를 통해 값을 수정하는 건 가능 합니다. 보통 레지스터 변수 반복횟수가 많을 경우 유용하게 사용하는 편입니다. (+ 지역 변수에만 사용할 수 있고 전역 변수에는 사용할 수 없습니다.)

#include <stdio.h>
#include <time.h>

int main()
{
	time_t start, end;
	double result;

	register int i, j = 0;
	// int i, j = 0;

	start = time(NULL);
	// 시간 측정 시작

	for (i = 0; i < 1000000; i++)
	{
		for (j = 0; j < 10000; j++)
		{
		}
	}

	end = time(NULL);
	// 시간 측정 끝
	result = (double)(end - start);

	printf("걸린 시간 : %lf\n\n", result);

	return 0;
}

결과 - 1
결과 - 2

음... 별로 차이가 안나네요. 더 반복횟수를 크게 했어야 했었을까요...?

 

+ 형 한정자

C언어에선 기억 부류 지정자 외에도 형을 한정시키는(제한 시키는) 형 한정자(type qualifier)이 있습니다.

형 한정자

 

C언어 핵심정리는 여기까지 하겠습니다.

부족한 정리를 봐주셔서 감사하고 지금까지 수고하셨습니다.

 

 

참고 자료 : 코딩 도장

https://dojang.io/

Comments