우선은 const로 사용하면 디버깅 심벌이 생성이 되기 때문에 watch window를 이용해서 상수의 값을 확인 하기 편합니다.
매크로는 한두개가 아닌 이상은 일일이 기억 할 수도 없는 노릇이고, 선언부를 찾아서 확인 하기도 매우 귀찮더군요. 특히 계산식을 매크로로 해놓으면 계산기를 옆에 두거나 띄워 놔야 하는데. 이것 또한 매우 귀찮은 일이죠.
그리고, VC6를 사용할땐 #define을 쓸땐 계산식을 이용하면 계산 하는데 제한이 있더군요. 임베디스 시스템의 메모리 맵을 그대로 가져 와서 사용할라고 했더니, 엉뚱한 값이 뛰쳐 나와서리, 그냥 속편하게 const를 사용하고 있습니다.
변수가 여러 모듈에서 사용된다면 #define을 쓴 다음 각 모듈에 조건부 컴파일 정의를 해두는 편이고
const는 메소드의 인자에 가끔 사용하는데 사실 저는 C언어나 C++이 업무에서 큰 비중을 차지하지 않고 C#을 주로 쓰기때문에
전처리기가 없는 이 언어에선 enum을 잘 사용합니다.
클래스내 enum이 아니라 네임스페이스로 구분되는 enum을 만들어 쓰는데 그러다 보니 한줄짜리 페이지도 더러 있지요. 8)
// 예..
switch(Arg)
{
case Enumerations.CurrSymbol.USD:
...
이유를 안썼는데.. 제가 코딩에서 가장 중요하게 여기는것은 명료성입니다. 그래서 이렇게 씁니다.
C 언어에서: const keyword로 선언한 const qualified identifier는, constant expression이 아닙니다. 즉, 배열 선언에서 크기를 지정할 때*, switch ()의 case label 등으로 쓰일 수 없습니다. 따라서 다음은 잘못된 것입니다.
const int i = 3;
int array[i];
C++ 언어에서: const keyword로 선언한 const qualified identifier는 constant expression이며, 배열 크기, switch label로 쓰일 수 있습니다. 따라서 위 코드는 올바른 C++ 코드입니다.
정수 상수 자체는 C, C++ 할 것 없이 constant expression이 될 수 있으므로 다음에 정의한 매크로는 constant expression입니다. (즉 아무 곳에서나 다 쓰일 수 있습니다):
#define LINE_MAX 256
흔히 #define으로 정의한 named constant는 디버거에서 볼 수 없어서 불편하다고 하시는데, 우리의 gcc와 gdb는 이런 매크로 값도 다 보여 줍니다.
int
main(void)
{
char buf[LINE_MAX];
int i = 3, j = 5;
int k;
k = MAX(i, j);
k = MIN(i, j);
return 0;
}
shar:~/tmp$ gcc -ggdb3 tmp.c
shar:~/tmp$ gdb -q a.out
Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) br main
Breakpoint 1 at 0x8048367: file tmp.c, line 9.
(gdb) r
Starting program: /home/cinsk/tmp/a.out
Breakpoint 1, main () at tmp.c:9
9 int i = 3, j = 5;
(gdb) p LINE_MAX
$1 = 256
(gdb) n
12 k = MAX(i, j);
(gdb) n
13 k = MIN(i, j);
(gdb) p k
$2 = 5
(gdb) p MAX(i, j)
$3 = 5
(gdb) macro expand MAX(i, j)
expands to: (((i) > (j)) ? (i) : (j))
(gdb) macro expand MAX(3, 5)
expands to: (((3) > (5)) ? (3) : (5))
(gdb) quit
The program is running. Exit anyway? (y or n) y
한가지, 위에서 "*" 표시한 부분에 설명을 빠뜨렸군요. constant expression이 아니더라도, C 언어에서는 가변 크기 배열을 지원하기 때문에, 처음 배열을 선언한 코드는, 함수와 같은 블럭 안에서 쓸 수 있습니다. 이 경우 array는 가변 배열(variable sized arrray)이기 때문에, 가변 배열에 따른 규칙들을 적용 받습니다.
프로젝트에서 몇 개의 상용 라이브러리를 링크해서 사용합니다. 그 중 한 라이브러리는 상수들을 선언할 때 조심스럽게 네임스페이스 안의 클래스 안에 enum으로 선언해서 사용합니다. 쓰기가 좀 불편하긴 하지만 알아보기 쉽고 충돌 문제가 적습니다.
그런 반면 다른 한 라이브러리는 NONE, DONE 같은 흔히 쓰일 수 있는 단어를 #define으로 때려 넣어 버렸습니다.
이 사실을 확인하기 전까지는 헤더 인클루드 순서 때문에 컴파일 에러가 발생하는 이상한 현상 때문에 힘든 리뷰 과정을 거쳐야만 했습니다..
----------------------------
May the F/OSS be with you..
const로 할 수 있는 곳은 가급적 const.
define만이 할 수 있는 부분은 define으로 합니다.
조금 더 구체적으로 알 수 있을까요?
상황봐서 고르기 때문에 남에게 설명할 만큼 정형화시켜서 말씀드리기 힘드네요. cinsk님이 쓰신, read-only로서의 "const"와 constant로서의 "const" 때문에 적어도 C에서는 문제가 쉽지 않다는 것을 깨닫나니 더욱 그렇습니다. C++ 컴파일러만 사용하다보니 -_-
##과 같은 define만이 할 수 있는 작업에는 define을 쓰지만 나머지는 가급적 const를 쓴다는 정도로밖에 설명할 수가 없네요.
이거 지난주 제가 job interview 할때 질문받았던 거군요.
그때 대답을 못해서 지난주 내내 열심히 공부했었지요.
항상 소잃고 외양간 고치기. ㅠ.ㅜ
const 는 volatile 과 더불어 c 언어의 처음 표준에는 없었다가 나중에 포함된 비교적 최근 예약어라고 할 수 있죠.
C의 const 는 기본적으로 C++ 에서 차용한 것이므로 그걸 염두에 두시는 것이 좋습니다.
보통 const 하면 상수로 정의된다는 것만 생각하기 쉬운데,
이걸 포인터와 같이 생각하면 조금 더 복잡해집니다.
int const *aaa;
이거랑
int *const aaa;
이것이 어떻게 다를까요?
전 지난주까지만 해도 몰랐습니다.
제가 배운 C 에는 없었던 것이고, C++ 도 사실 열심히 안한거죠. (헤헤)
기본적으로 int const *aaa; 라고 하면 pointer to constant int 즉,
정수 값 자체가 상수인 포인터를 말합니다.
그러니깐 aaa 에 다른 상수값 포인터를 치환해도 에러가 안나죠.
다만, 일단 포인터를 가지고 있으면 그 정수 값은 상수이기 때문에 치환이 안됩니다.
반대로 int *const aaa; 라고 하면 constant pointer to int,
즉, 포인터 자체가 상수가 됩니다.
이때는 거꾸로 정수값 자체는 바꿀 수 있지만, 포인터는 절대 바꾸면 안되죠.
보통 정해진 i/o 번지에 직접 메모리 엑세스를 하는 주변기기와의 통신이나
인터럽트 루틴 등에서 이런 방법을 쓰곤 합니다.
그에 반해서 #define 문은 단순히 매크로일 뿐이므로 완전히 다른 용도라고 봐야죠.
물론 포인터(배열)가 아닌 기본형 변수에 const 를 붙이면 메모리 좀 더 차지하는 것 외엔 별 차이를 못 느끼실 수 있지만,
위의 경우를 생각해보시면 엄청난 차이가 있단걸 알 수 있죠?
설명이 잘 되었나 몰라요.
암튼 잘 공부하셔서 저같은 실수를 되풀이하지 마시길 바래요. *꾸뻑*
vio:
PS> C++ 에서는 Object 이 대부분 포인터로 선언됩니다. 그렇기에 위의 두가지 차이가 더욱 극명하게 드러나죠.
아, 제 설명에 틀린 부분이 있었군요. 맞습니다. const 로 지정한 변수만 상수처럼 작용하는 것이지, 대상 자체가 상수가 되는건 아니지요.
하지만, 표준에 처음부터 있었다는 말은 정확하지 않습니다.
만일 ANSI 표준만을 말씀하신다면 맞는 말이지만, C의 처음 표준은 AT&T 에서 UNIX 와 함께 개발했던 K&R 표준(1978)을 말합니다.
ANSI 의 C standard committee 는 1983년에야 시작됩니다.
실제로 제가 C 를 배우던 1989~1990년만 해도 컴파일러 문제때문에 C 표준 하면 ANSI 표준이냐 K&R 표준이냐를 지칭해야만 했습니다.
참고로 최초의 ANSI 표준은 C90가 아니라 C89인걸로 알고 있습니다. (궁극적으로 같은 것이긴 하네요 ^^)
doldori wrote:
violino wrote:
const 는 volatile 과 더불어 c 언어의 처음 표준에는 없었다가 나중에 포함된 비교적 최근 예약어라고 할 수 있죠.
C의 const 는 기본적으로 C++ 에서 차용한 것이므로 그걸 염두에 두시는 것이 좋습니다.
실은 그 반대입니다. const와 volatile은 C의 처음 표준(C90)부터 있었답니다.
violino wrote:
다만, 일단 포인터를 가지고 있으면 그 정수 값은 상수이기 때문에 치환이 안됩니다.
좀 오해의 소지가 있어서 부연하면 const T* 형의 포인터가 가리킨다고 해서 그 대상이
상수가 되는 것은 아닙니다. 그 포인터를 통해서 변경하는 것이 불가능할 뿐이고
그 대상 자체는 여전히 변경 가능합니다.
int i;
int* p = &i;
const int* cp = &i;
*cp = 0; // error
*p = 0; // ok
i = 0; // ok
제가 위에서 "실은 그 반대"라고 한 말은 "C의 const 는 기본적으로 C++ 에서
차용한 것"이 아니라는 뜻이었습니다만, 표준에 대해서도 좀 얘기를 하면...
violino wrote:
하지만, 표준에 처음부터 있었다는 말은 정확하지 않습니다.
만일 ANSI 표준만을 말씀하신다면 맞는 말이지만, C의 처음 표준은 AT&T 에서 UNIX 와 함께 개발했던 K&R 표준(1978)을 말합니다.
ANSI 의 C standard committee 는 1983년에야 시작됩니다.
실제로 제가 C 를 배우던 1989~1990년만 해도 컴파일러 문제때문에 C 표준 하면 ANSI 표준이냐 K&R 표준이냐를 지칭해야만 했습니다.
참고로 최초의 ANSI 표준은 C90가 아니라 C89인걸로 알고 있습니다. (궁극적으로 같은 것이긴 하네요 ^^)
일단 "K&R 표준"이라는 말씀은 표준의 의미를 너무 확대해석하신 것입니다.
보통 K&R C라고 부르는 C는 TCPL 초판에서 기술된 C를 뜻합니다. 그런데 이것은
표준이 제정되기 이전에 레퍼런스로서의 역할을 했고 표준화 과정에서 기반이 되는
문서였을 뿐 공식적인 절차를 거쳐서 제정된 표준과는 내용이나 무게가 전혀 다릅니다.
C++에도 이와 비슷한 사례가 있습니다. 아시다시피 C++ 표준은 98년도에 제정됐는데
그 이전에는 The Annotated C++ Reference Manual (ARM)이 레퍼런스였습니다.
이 역시 표준화의 기반이 되었지만 아무도 ARM을 표준이라고 부르지는 않습니다.
그리고 C89/C90에 대해서 변명을 좀 하면, 말씀대로 C89와 C90은 실질적으로
동일한 내용입니다. 그런데 C89는 ANSI 표준(미국 표준)이고 C90은 국제 표준이라는
점이 다르죠. 그리고 국제 표준화에는 우리나라도 참여합니다. 우리나라 입장에서는
최초 표준이 미국 표준이 아니라 국제 표준이라는 의미에서 의도적으로 C90을 썼습니다.
처음 C 가 개발된 이후 ANSI 표준이 제정되기까지 많은 일들이 있었습니다.
대표적인 일이 80년도부터 C++ 이 개발되었고, 그사이 C 컴파일러들도 몇몇 나와서 이미 K&R 규격(표준이란 말에 오해의 여지가 있다면 규격이라고 하겠습니다)이 사실상 비공식 산업 표준처럼 되어 있었습니다.
제가 말씀드렸듯이 ANSI 표준이 나왔다고 해서 바로 모든 시스템이 ANSI를 지원한것도 아니었고요.
그래서 얼마전까지만 해도 C 에는 사실상 두개의 표준이 존재하는 것이나 다름없었습니다.
요즘도 K&R 규격을 지원하는 컴파일러가 나온다고 생각되진 않지만, 분명히 업계에서 오랬동안 사용되던 규격입니다.
표준이란 말을 넘 엄격하게 해석하신듯 합니다. 말씀하신 뜻이나 표준 제정 과정등은 너무나도 잘 알고 있으니 오해가 마시고요, 결국 제가 용어 선택을 잘못해서 혼동을 일으킨 것이 되어버렸네요. 죄송합니다. *꾸벅*
사족인데, 제가 한국에 있을때 표준하고 밀접하게 연관된 일을 했었거든요. ^^
앗..사람들이 #define만 죽어라 쓰길래const가 있었는지
앗..
사람들이 #define만 죽어라 쓰길래
const가 있었는지 잠시 까먹고 있었습니다. :lol:
회사 다니면서 더 바보 되는듯~~
const 하고 define 하고는 많이 차이가 나지 않나요?cons
const 하고 define 하고는 많이 차이가 나지 않나요?
const int 하면 read-only data memory 그 값이 올라가는것이고 define 는 pre-compiling 에서 치환되는 값이지요. 즉 메모리를 차지하지는 않습니다.
상황에 따라 다르게 쓸려면 동일한 값으로 변수들을 초기화할때는 define 을 쓰면 좋겠군요. 이럴때 만약 const 변수로 초기화 하면 명령어들이 늘어나는 경우가 되니 피해야 하겠죠.
임베디드 같은 열악한 환경이면 당연히 define을 이용한 매크로를 사용
임베디드 같은 열악한 환경이면 당연히 define을 이용한 매크로를 사용합니다만.
우선은 const로 사용하면 디버깅 심벌이 생성이 되기 때문에 watch window를 이용해서 상수의 값을 확인 하기 편합니다.
매크로는 한두개가 아닌 이상은 일일이 기억 할 수도 없는 노릇이고, 선언부를 찾아서 확인 하기도 매우 귀찮더군요. 특히 계산식을 매크로로 해놓으면 계산기를 옆에 두거나 띄워 놔야 하는데. 이것 또한 매우 귀찮은 일이죠.
그리고, VC6를 사용할땐 #define을 쓸땐 계산식을 이용하면 계산 하는데 제한이 있더군요. 임베디스 시스템의 메모리 맵을 그대로 가져 와서 사용할라고 했더니, 엉뚱한 값이 뛰쳐 나와서리, 그냥 속편하게 const를 사용하고 있습니다.
디버깅이 편한 이유로 임베디드가 아닌 이상은 const를 더 선호 합니다.
높이 날다 떨어지면.
아푸다 ㅡ,.ㅡ
C라면 define, C++이라면 const
C라면 define, C++이라면 const
const는 변수형을 지정할 수 있기 때문에 #define 보다 더 안전
const는 변수형을 지정할 수 있기 때문에 #define 보다 더 안전합니다. 일반적인 상수 외에 const를 사용하는 경우는.. 사전류의 읽기만 하는 값 관리자의 반환값, 변경하면 안 되는 개체의 포인터를 함수에 넘길 때 .. 등등
----------------------------
May the F/OSS be with you..
C++ 에서 특정 상수 값을 선언할 때는 enum 을 이용합니다. 메모리
C++ 에서 특정 상수 값을 선언할 때는 enum 을 이용합니다. 메모리 영역에 올리지 않고 심볼이 만들어지므로 디버깅도 편합니다.
-----------------------------------------------------------------------
GPL 오픈소스 윈도우용 이미지 뷰어 ZViewer - http://zviewer.wimy.com
블로그 : http://blog.wimy.com
메모리 영역에 올리지 않는 다는 것이 정확히 무슨의미인가요??
무슨의미인지 잘 모르겠네요 ㅠㅠ
#define과 같은 의미로 사용된 const라면 컴파일러님께서 친절하게
#define과 같은 의미로 사용된 const라면 컴파일러님께서 친절하게 삭제해주십니다. 메모리에 올라가지 않죠. 최적화의 과정은 오묘합니다.
[quote="Anonymous"]#define과 같은 의미로 사용된 c
하지만 디버깅 모드로 컴파일 하고 빌드 한다면 어떨까요? :)
디버그 모드에서도 어느정도 최적화를 할 수 있고 하긴 하지만 보통 디버깅을 위한 프로그램은 최적화를 하지 않습니다. 디버그 모드에서는 const 변수가 메모리에 잘 살아 있겠고요.
디버깅 모드로 배포하지는 않으니 크게 고려치 않아도
디버깅 모드로 배포하지는 않으니 크게 고려치 않아도 될거 같습니다.
Release 모드로 해야 최적화가 제대로 되더라구요.
변수가 여러 모듈에서 사용된다면 #define을 쓴 다음 각 모듈에 조건
변수가 여러 모듈에서 사용된다면 #define을 쓴 다음 각 모듈에 조건부 컴파일 정의를 해두는 편이고
const는 메소드의 인자에 가끔 사용하는데 사실 저는 C언어나 C++이 업무에서 큰 비중을 차지하지 않고 C#을 주로 쓰기때문에
전처리기가 없는 이 언어에선 enum을 잘 사용합니다.
클래스내 enum이 아니라 네임스페이스로 구분되는 enum을 만들어 쓰는데 그러다 보니 한줄짜리 페이지도 더러 있지요. 8)
이유를 안썼는데.. 제가 코딩에서 가장 중요하게 여기는것은 명료성입니다. 그래서 이렇게 씁니다.
const 선호합니다. 매크로는 type, scope, context 같
const 선호합니다. 매크로는 type, scope, context 같은 것을 개무시하기 때문에.
저를 열받게 했던 예입니다.
임베디드 쪽 하시는가 보군요.전 PC쪽 할땐 const변수를 MB단위
임베디드 쪽 하시는가 보군요.
전 PC쪽 할땐 const변수를 MB단위로 써본적이 없어서 디버그 모드에서 const변수에 의한 메모리 사용을 걱정해 본적이 없습니다, 메모리에 꽤나 민감한 시스템을 사용하시나 봅니다. :shock:
높이 날다 떨어지면.
아푸다 ㅡ,.ㅡ
C 언어에서: const keyword로 선언한 const qualifi
C 언어에서: const keyword로 선언한 const qualified identifier는, constant expression이 아닙니다. 즉, 배열 선언에서 크기를 지정할 때*, switch ()의 case label 등으로 쓰일 수 없습니다. 따라서 다음은 잘못된 것입니다.
C++ 언어에서: const keyword로 선언한 const qualified identifier는 constant expression이며, 배열 크기, switch label로 쓰일 수 있습니다. 따라서 위 코드는 올바른 C++ 코드입니다.
정수 상수 자체는 C, C++ 할 것 없이 constant expression이 될 수 있으므로 다음에 정의한 매크로는 constant expression입니다. (즉 아무 곳에서나 다 쓰일 수 있습니다):
#define LINE_MAX 256
흔히 #define으로 정의한 named constant는 디버거에서 볼 수 없어서 불편하다고 하시는데, 우리의 gcc와 gdb는 이런 매크로 값도 다 보여 줍니다.
$ cat tmp.c
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define LINE_MAX 256
int
main(void)
{
char buf[LINE_MAX];
int i = 3, j = 5;
int k;
k = MAX(i, j);
k = MIN(i, j);
return 0;
}
shar:~/tmp$ gcc -ggdb3 tmp.c
shar:~/tmp$ gdb -q a.out
Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) br main
Breakpoint 1 at 0x8048367: file tmp.c, line 9.
(gdb) r
Starting program: /home/cinsk/tmp/a.out
Breakpoint 1, main () at tmp.c:9
9 int i = 3, j = 5;
(gdb) p LINE_MAX
$1 = 256
(gdb) n
12 k = MAX(i, j);
(gdb) n
13 k = MIN(i, j);
(gdb) p k
$2 = 5
(gdb) p MAX(i, j)
$3 = 5
(gdb) macro expand MAX(i, j)
expands to: (((i) > (j)) ? (i) : (j))
(gdb) macro expand MAX(3, 5)
expands to: (((3) > (5)) ? (3) : (5))
(gdb) quit
The program is running. Exit anyway? (y or n) y
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://cinsk.github.io/cfaqs/
한가지, 위에서 "*" 표시한 부분에 설명을 빠뜨렸군요. constant
한가지, 위에서 "*" 표시한 부분에 설명을 빠뜨렸군요. constant expression이 아니더라도, C 언어에서는 가변 크기 배열을 지원하기 때문에, 처음 배열을 선언한 코드는, 함수와 같은 블럭 안에서 쓸 수 있습니다. 이 경우 array는 가변 배열(variable sized arrray)이기 때문에, 가변 배열에 따른 규칙들을 적용 받습니다.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://cinsk.github.io/cfaqs/
[quote="cinsk"]흔히 #define으로 정의한 named co
헉.. 역시 gdb 좋군요.
높이 날다 떨어지면.
아푸다 ㅡ,.ㅡ
define, const 이외에 enum도 상당히 유용하게 사용할 수 있
define, const 이외에 enum도 상당히 유용하게 사용할 수 있습니다.
- 죠커's blog / HanIRC:#CN
최근에 #define 상수 때문에 문제를 겪었던 적이 있죠.프로젝
최근에 #define 상수 때문에 문제를 겪었던 적이 있죠.
프로젝트에서 몇 개의 상용 라이브러리를 링크해서 사용합니다. 그 중 한 라이브러리는 상수들을 선언할 때 조심스럽게 네임스페이스 안의 클래스 안에 enum으로 선언해서 사용합니다. 쓰기가 좀 불편하긴 하지만 알아보기 쉽고 충돌 문제가 적습니다.
그런 반면 다른 한 라이브러리는 NONE, DONE 같은 흔히 쓰일 수 있는 단어를 #define으로 때려 넣어 버렸습니다.
이 사실을 확인하기 전까지는 헤더 인클루드 순서 때문에 컴파일 에러가 발생하는 이상한 현상 때문에 힘든 리뷰 과정을 거쳐야만 했습니다..
----------------------------
May the F/OSS be with you..
Re: define과 const 어느쪽을 선호 하십니까? 그리고 선호하는 이유는?
const로 할 수 있는 곳은 가급적 const.
define만이 할 수 있는 부분은 define으로 합니다.
Re: define과 const 어느쪽을 선호 하십니까? 그리고 선호하는 이유는?
조금 더 구체적으로 알 수 있을까요?
- 죠커's blog / HanIRC:#CN
Re: define과 const 어느쪽을 선호 하십니까? 그리고 선호하는 이유는?
상황봐서 고르기 때문에 남에게 설명할 만큼 정형화시켜서 말씀드리기 힘드네요. cinsk님이 쓰신, read-only로서의 "const"와 constant로서의 "const" 때문에 적어도 C에서는 문제가 쉽지 않다는 것을 깨닫나니 더욱 그렇습니다. C++ 컴파일러만 사용하다보니 -_-
##과 같은 define만이 할 수 있는 작업에는 define을 쓰지만 나머지는 가급적 const를 쓴다는 정도로밖에 설명할 수가 없네요.
[code:1]char *strcpy(char *dest, con
char *strcpy(char *dest, const char *src);
요런식으로 포인터를 function인자로 넘길때,
변경해서는 안되는 것에 const를 잡아주는 것 외에는
거의 무조건 define이네염...
enum이 조아요~
enum이 조아요~
ㅡ_ㅡ;
[quote="CN"]define, const 이외에 enum도 상당히
enum파 한 분 더 등장이군요 ! :-)
- 죠커's blog / HanIRC:#CN
[quote="CN"][quote="CN"]define, const 이외
저도 enum 이것 때문에 프로그램 짤때 좀 편하게 짠 것 같습니다 :D
일찍 일어나는 새가 밥 잘 찾아 먹는다.:D
const 는...
이거 지난주 제가 job interview 할때 질문받았던 거군요.
그때 대답을 못해서 지난주 내내 열심히 공부했었지요.
항상 소잃고 외양간 고치기. ㅠ.ㅜ
const 는 volatile 과 더불어 c 언어의 처음 표준에는 없었다가 나중에 포함된 비교적 최근 예약어라고 할 수 있죠.
C의 const 는 기본적으로 C++ 에서 차용한 것이므로 그걸 염두에 두시는 것이 좋습니다.
보통 const 하면 상수로 정의된다는 것만 생각하기 쉬운데,
이걸 포인터와 같이 생각하면 조금 더 복잡해집니다.
int const *aaa;
이거랑
int *const aaa;
이것이 어떻게 다를까요?
전 지난주까지만 해도 몰랐습니다.
제가 배운 C 에는 없었던 것이고, C++ 도 사실 열심히 안한거죠. (헤헤)
기본적으로 int const *aaa; 라고 하면 pointer to constant int 즉,
정수 값 자체가 상수인 포인터를 말합니다.
그러니깐 aaa 에 다른 상수값 포인터를 치환해도 에러가 안나죠.
다만, 일단 포인터를 가지고 있으면 그 정수 값은 상수이기 때문에 치환이 안됩니다.
반대로 int *const aaa; 라고 하면 constant pointer to int,
즉, 포인터 자체가 상수가 됩니다.
이때는 거꾸로 정수값 자체는 바꿀 수 있지만, 포인터는 절대 바꾸면 안되죠.
보통 정해진 i/o 번지에 직접 메모리 엑세스를 하는 주변기기와의 통신이나
인터럽트 루틴 등에서 이런 방법을 쓰곤 합니다.
그에 반해서 #define 문은 단순히 매크로일 뿐이므로 완전히 다른 용도라고 봐야죠.
물론 포인터(배열)가 아닌 기본형 변수에 const 를 붙이면 메모리 좀 더 차지하는 것 외엔 별 차이를 못 느끼실 수 있지만,
위의 경우를 생각해보시면 엄청난 차이가 있단걸 알 수 있죠?
설명이 잘 되었나 몰라요.
암튼 잘 공부하셔서 저같은 실수를 되풀이하지 마시길 바래요. *꾸뻑*
vio:
PS> C++ 에서는 Object 이 대부분 포인터로 선언됩니다. 그렇기에 위의 두가지 차이가 더욱 극명하게 드러나죠.
[quote="오만한 리눅서"]요런식으로 포인터를 function인자
저도 어지간하면 윗분과 같이 function쪽 외에는 거의 define으로 지르는거 같네요. ㅎㅎ
------------------------------------------------------
아직은 젊다. 모든 것을 할 수 있는 나이란 말이지.
Re: const 는...
실은 그 반대입니다. const와 volatile은 C의 처음 표준(C90)부터 있었답니다.
좀 오해의 소지가 있어서 부연하면 const T* 형의 포인터가 가리킨다고 해서 그 대상이
상수가 되는 것은 아닙니다. 그 포인터를 통해서 변경하는 것이 불가능할 뿐이고
그 대상 자체는 여전히 변경 가능합니다.
C99 표준의 VLA에서는 배열크기를 const 한정자로 지정할 수 있습니다.
C99 표준의 VLA에서는 배열크기를 const 한정자로 지정할 수 있습니다.
따라서 다음과 같은 코드도 가능합니다.
하지만, 이는 C99 표준안에 포함된 내용이므로 C99 표준안을 지원하는 임플리먼테이션에서만 가능합니다.
========================================
* The truth will set you free.
가변 길이 배열
가변 길이 배열은 꼭 const가 아니어도 선언할 수 있지 않나요?
제가 잘 못 알고 있는 건가요······?
Re: const 는...
아, 제 설명에 틀린 부분이 있었군요. 맞습니다. const 로 지정한 변수만 상수처럼 작용하는 것이지, 대상 자체가 상수가 되는건 아니지요.
하지만, 표준에 처음부터 있었다는 말은 정확하지 않습니다.
만일 ANSI 표준만을 말씀하신다면 맞는 말이지만, C의 처음 표준은 AT&T 에서 UNIX 와 함께 개발했던 K&R 표준(1978)을 말합니다.
ANSI 의 C standard committee 는 1983년에야 시작됩니다.
실제로 제가 C 를 배우던 1989~1990년만 해도 컴파일러 문제때문에 C 표준 하면 ANSI 표준이냐 K&R 표준이냐를 지칭해야만 했습니다.
참고로 최초의 ANSI 표준은 C90가 아니라 C89인걸로 알고 있습니다. (궁극적으로 같은 것이긴 하네요 ^^)
Re: const 는...
제가 위에서 "실은 그 반대"라고 한 말은 "C의 const 는 기본적으로 C++ 에서
차용한 것"이 아니라는 뜻이었습니다만, 표준에 대해서도 좀 얘기를 하면...
일단 "K&R 표준"이라는 말씀은 표준의 의미를 너무 확대해석하신 것입니다.
보통 K&R C라고 부르는 C는 TCPL 초판에서 기술된 C를 뜻합니다. 그런데 이것은
표준이 제정되기 이전에 레퍼런스로서의 역할을 했고 표준화 과정에서 기반이 되는
문서였을 뿐 공식적인 절차를 거쳐서 제정된 표준과는 내용이나 무게가 전혀 다릅니다.
C++에도 이와 비슷한 사례가 있습니다. 아시다시피 C++ 표준은 98년도에 제정됐는데
그 이전에는 The Annotated C++ Reference Manual (ARM)이 레퍼런스였습니다.
이 역시 표준화의 기반이 되었지만 아무도 ARM을 표준이라고 부르지는 않습니다.
그리고 C89/C90에 대해서 변명을 좀 하면, 말씀대로 C89와 C90은 실질적으로
동일한 내용입니다. 그런데 C89는 ANSI 표준(미국 표준)이고 C90은 국제 표준이라는
점이 다르죠. 그리고 국제 표준화에는 우리나라도 참여합니다. 우리나라 입장에서는
최초 표준이 미국 표준이 아니라 국제 표준이라는 의미에서 의도적으로 C90을 썼습니다.
이거 넘 곁다리로 많이 빠지는 것 같지만..
처음 C 가 개발된 이후 ANSI 표준이 제정되기까지 많은 일들이 있었습니다.
대표적인 일이 80년도부터 C++ 이 개발되었고, 그사이 C 컴파일러들도 몇몇 나와서 이미 K&R 규격(표준이란 말에 오해의 여지가 있다면 규격이라고 하겠습니다)이 사실상 비공식 산업 표준처럼 되어 있었습니다.
제가 말씀드렸듯이 ANSI 표준이 나왔다고 해서 바로 모든 시스템이 ANSI를 지원한것도 아니었고요.
그래서 얼마전까지만 해도 C 에는 사실상 두개의 표준이 존재하는 것이나 다름없었습니다.
요즘도 K&R 규격을 지원하는 컴파일러가 나온다고 생각되진 않지만, 분명히 업계에서 오랬동안 사용되던 규격입니다.
표준이란 말을 넘 엄격하게 해석하신듯 합니다. 말씀하신 뜻이나 표준 제정 과정등은 너무나도 잘 알고 있으니 오해가 마시고요, 결국 제가 용어 선택을 잘못해서 혼동을 일으킨 것이 되어버렸네요. 죄송합니다. *꾸벅*
사족인데, 제가 한국에 있을때 표준하고 밀접하게 연관된 일을 했었거든요. ^^
C++에서 const, volatile 등을 가져왔다는 말은 그전에 제가 보았던 레퍼런스들을 참고한 것이고, 최초 K&R 버전과의 차이나 ANSI 표준이 제정된 시기로 보았을때. 어느정도 타당성이 있다고 생각되어 쓴 말입니다. BellLab 홈페이지의 C history (http://cm.bell-labs.com/cm/cs/who/dmr/chist.html) 에 보면 ANSI 의 C 표준화 커미티였던 X3J11 에서 몇가지 추가를 했는데 예를 들어 const and volatile ... 이라고 설명을 하고 있습니다. 제가 const, volatile 의 C language 에서의 용례를 찾다가 위키피디아(http://en.wikipedia.org/wiki/C_programming_language)와 영국의 C 책에 관한 사이트(http://publication.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html)에서 모두 C++에서 차용(borrowed from c++)했다는 문구를 봤습니다. (사실 검색해보면 이같은 설명은 상당히 많은 학술 사이트에서 발견됩니다) 또한, 저도 오늘 다시 조사하다가 안 것인데, C 를 처음 개발한 일원인 Dennis Ritchie 는 자기가 왜 const, volatile 을 추가하는것에 반대하고 그 이유로 X3J11 을 맘에 안들어하는지에 대한 자세한 노트도 남기고 있습니다. (http://www.lysator.liu.se/c/dmr-on-noalias.html)
C 의 개발에 여러가지 재미있는 사실들이 많군요.
vio:
Re: 이거 넘 곁다리로 많이 빠지는 것 같지만..
그렇군요. 제가 잘못 알고 있었습니다. C의 표준화 과정에서 const/volatile 형 한정어,
함수 원형 선언 등을 C++로부터 차용했다고 하는군요. 바로잡아 주셔서 감사합니다.
ps. 앞으로 많은 글로 제 무지를 드러내야 하겠습니다. 그래야 고쳐질 테니까요. :-)
Re: define과 const 어느쪽을 선호 하십니까? 그리고 선호하는 이유는?
선호성은 잘모르나,
개발시는 const를
적용시는 object-like macro를
사용하면 좋을 것 같습니다.
const가 낫죠. #define n
const가 낫죠.
Real programmers /* don't */ comment their code.
If it was hard to write, it should be /* hard to */ read.
댓글 달기