int main(void);
int main(int argc, char *argv[]);
int main(int argc, char **argv);
/* argv 데이타와 주소를 변경하고 싶지 않을 때 */
int main(int argc, const char * const argv[]);
int main(int argc, const char * const * argv);
int main(int argc, char *argv[]);
int main(int argc, char **argv);
/* argv 데이타와 주소를 변경하고 싶지 않을 때 */
int main(int argc, const char * const argv[]);
int main(int argc, const char * const * argv);
명령행 데이타를 argc, argv 형태로 변환하는 함수
#include <stdio.h>
#include <string.h>
/*! \brief 최대한 받아들이는 argument 갯수 */
#define MAX_ARG 10
/*! \brief argv용 버퍼의 최대 크기 */
#define MAX_CMDLEN 256
/*! \brief 입력된 명령행 버퍼를 argc, argv 형태로 변환하는 함수
*
* \param buf : 명령행으로 입력된 버퍼 포인터
* \param argv [OUT] : 변환된 argv 형태의 포인터 배열
*
* \return argc 값 */
int parse_argument( const char *buf, char *argv[])
{
int i,j;
char ch;
int len;
int argc;
int firstChar;
/* 외부에서 포인터로 접근하기 위한 static 배열 */
static char argv_buf[MAX_CMDLEN+1];
len = strlen( buf);
argc = 0;
firstChar = 1;
for( i=0,j=0; i<len; ++i) {
ch = buf[i];
/* 공백 문자다. 하나의 argument 끝 */
if( ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
if( firstChar == 0) {
argv_buf[j] = '\0';
++j;
++argc;
argv[argc] = NULL;
firstChar = 1;
if( j == MAX_CMDLEN || argc == MAX_ARG) {
break;
}
}
continue;
}
if( firstChar == 1) {
argv[argc] = &argv_buf[j];
firstChar = 0;
}
argv_buf[j] = ch;
++j;
if( j == MAX_CMDLEN) {
argv_buf[j] = '\0';
break;
}
}
if( firstChar == 0) {
argv_buf[j] = '\0';
++argc;
argv[argc] = NULL;
}
return argc;
}
/*! \brief 테스트 함수 */
void CTestDlg::TestFunc(void)
{
int i;
const char *input = " aaaaaaaaa abc 333 444 555 777 bbbbbbbb ";
int argc;
char *argv[MAX_ARG];
argc = parse_argument( input, argv);
printf("argc : %d\n", argc);
for( i=0; i<argc; i++) {
printf("%d : %s\n", i, argv[i]);
}
printf("argv[argc] : %d\n", argv[argc]);
}
#include <string.h>
/*! \brief 최대한 받아들이는 argument 갯수 */
#define MAX_ARG 10
/*! \brief argv용 버퍼의 최대 크기 */
#define MAX_CMDLEN 256
/*! \brief 입력된 명령행 버퍼를 argc, argv 형태로 변환하는 함수
*
* \param buf : 명령행으로 입력된 버퍼 포인터
* \param argv [OUT] : 변환된 argv 형태의 포인터 배열
*
* \return argc 값 */
int parse_argument( const char *buf, char *argv[])
{
int i,j;
char ch;
int len;
int argc;
int firstChar;
/* 외부에서 포인터로 접근하기 위한 static 배열 */
static char argv_buf[MAX_CMDLEN+1];
len = strlen( buf);
argc = 0;
firstChar = 1;
for( i=0,j=0; i<len; ++i) {
ch = buf[i];
/* 공백 문자다. 하나의 argument 끝 */
if( ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
if( firstChar == 0) {
argv_buf[j] = '\0';
++j;
++argc;
argv[argc] = NULL;
firstChar = 1;
if( j == MAX_CMDLEN || argc == MAX_ARG) {
break;
}
}
continue;
}
if( firstChar == 1) {
argv[argc] = &argv_buf[j];
firstChar = 0;
}
argv_buf[j] = ch;
++j;
if( j == MAX_CMDLEN) {
argv_buf[j] = '\0';
break;
}
}
if( firstChar == 0) {
argv_buf[j] = '\0';
++argc;
argv[argc] = NULL;
}
return argc;
}
/*! \brief 테스트 함수 */
void CTestDlg::TestFunc(void)
{
int i;
const char *input = " aaaaaaaaa abc 333 444 555 777 bbbbbbbb ";
int argc;
char *argv[MAX_ARG];
argc = parse_argument( input, argv);
printf("argc : %d\n", argc);
for( i=0; i<argc; i++) {
printf("%d : %s\n", i, argv[i]);
}
printf("argv[argc] : %d\n", argv[argc]);
}
main 함수의 두번째 인자(argv)가 왜 const가 아닌가?
* 다음 테스트 프로그램을 돌려보자.
int main(int argc, char *argv[])
{
int i;
printf("argc : %d\n", argc);
for( i=0; i<argc, ++i) {
printf("%d : %s\n", i, argv[i]);
}
strcpy( argv[0], "0123456789012345678901234567890123456789012345678901234567890123456789");
printf("argc : %d\n", argc);
for( i=0; i<argc, ++i) {
printf("%d : %s\n", i, argv[i]);
}
}
{
int i;
printf("argc : %d\n", argc);
for( i=0; i<argc, ++i) {
printf("%d : %s\n", i, argv[i]);
}
strcpy( argv[0], "0123456789012345678901234567890123456789012345678901234567890123456789");
printf("argc : %d\n", argc);
for( i=0; i<argc, ++i) {
printf("%d : %s\n", i, argv[i]);
}
}
* 이 테스트 프로그램을 위 parse_argument 함수에 적용해보면 똑 같은 결과가 나옴을 알 수 있다.
* 즉, 내부 구현이 비슷함을 알 수 있다.
표준에서의 main 함수의 두번째 인자의 const 여부
* C99에서의 언급
The parameters argc and argv and the strings pointed to by the argv array shall
be modifiable by the program, and retain their last-stored values between
program startup and program termination.
be modifiable by the program, and retain their last-stored values between
program startup and program termination.
* C90 그리고 C++98 에서의 언급
* C++은 C90에 기초하고, C90 표준을 subset로 가지고 있다.
In C90 it is mentioned:
"Program startup"
The function called at program startup is named main . The
implementation declares no prototype for this function. It can be
defined with no parameters:
int main(void) { /*...*/ }
or with two parameters (referred to here as argc and argv , though any
names may be used, as they are local to the function in which they are
declared):
int main(int argc, char *argv[]) { /*...*/ }
If they are defined, the parameters to the main function shall obey
the following constraints:
* The value of argc shall be nonnegative.
* argv[argc] shall be a null pointer.
* If the value of argc is greater than zero, the array members
argv[0] through argv[argc-1] inclusive shall contain pointers to
strings, which are given implementation-defined values by the host
environment prior to program startup. The intent is to supply to the
program information determined prior to program startup from elsewhere
in the hosted environment. If the host environment is not capable of
supplying strings with letters in both upper-case and lower-case, the
implementation shall ensure that the strings are received in
lower-case.
* If the value of argc is greater than zero, the string pointed to by
argv[0] represents the program name ;argv[0][0] shall be the null
character if the program name is not available from the host
environment. If the value of argc is greater than one, the strings
pointed to by argv[1] through argv[argc-1] represent the program
parameters .
* The parameters argc and argv and the strings pointed to by the argv
array shall be modifiable by the program, and retain their
last-stored values between program startup and program termination.
"Program startup"
The function called at program startup is named main . The
implementation declares no prototype for this function. It can be
defined with no parameters:
int main(void) { /*...*/ }
or with two parameters (referred to here as argc and argv , though any
names may be used, as they are local to the function in which they are
declared):
int main(int argc, char *argv[]) { /*...*/ }
If they are defined, the parameters to the main function shall obey
the following constraints:
* The value of argc shall be nonnegative.
* argv[argc] shall be a null pointer.
* If the value of argc is greater than zero, the array members
argv[0] through argv[argc-1] inclusive shall contain pointers to
strings, which are given implementation-defined values by the host
environment prior to program startup. The intent is to supply to the
program information determined prior to program startup from elsewhere
in the hosted environment. If the host environment is not capable of
supplying strings with letters in both upper-case and lower-case, the
implementation shall ensure that the strings are received in
lower-case.
* If the value of argc is greater than zero, the string pointed to by
argv[0] represents the program name ;argv[0][0] shall be the null
character if the program name is not available from the host
environment. If the value of argc is greater than one, the strings
pointed to by argv[1] through argv[argc-1] represent the program
parameters .
* The parameters argc and argv and the strings pointed to by the argv
array shall be modifiable by the program, and retain their
last-stored values between program startup and program termination.
2008/07/09 19:41
Subversion의 commit과 Trac 연동하기...(Subversion, Trac, post-commit, trac-post-commit-hook)
2008/07/09 19:41 in 버전관리

Subversion에서 commit하면 자동으로 Trac의 티켓 닫기
일단 다음과 같이 가정합니다.
- Subversion 저장소 : /var/TEST
- Trac 저장소 : /var/TEST.TRAC
Subversion의 post-commit 훅 스크립트
- /var/TEST/hooks/post-commit 스크립트 파일
- 원래의 파일 이름은 post-commit.tmpl 입니다. 이 파일의 이름을 post-commit 으로 변경하고, 실행 속성을 주어야 합니다.
SVNLOOK=/usr/local/bin/svnlook
REPOS="$1"
REV="$2"
LOG=`$SVNLOOK log -r "$REV" "$REPOS"`
AUTHOR=`$SVNLOOK author -r "$REV" "$REPOS"`
DIRS="`$SVNLOOK dirs-changed -r "$REV" "$REPOS"`"
$REPOS/hooks/trac-post-commit-hook.py -p /var/TEST.TRAC -r "$REV" -u "$AUTHOR" -m "$LOG"
REPOS="$1"
REV="$2"
LOG=`$SVNLOOK log -r "$REV" "$REPOS"`
AUTHOR=`$SVNLOOK author -r "$REV" "$REPOS"`
DIRS="`$SVNLOOK dirs-changed -r "$REV" "$REPOS"`"
$REPOS/hooks/trac-post-commit-hook.py -p /var/TEST.TRAC -r "$REV" -u "$AUTHOR" -m "$LOG"
Trac의 trac-post-commit-hook.py 파일
- 사용하고 있는 trac의 소스에 보면 contrib/trac-post-commit-hook 파일이 있습니다.
- 이 파일을 /var/TEST/hooks 디렉토리에 복사합니다. 이 위치는 post-commit 파일에 명시된 위치와 동일합니다.
주의 사항
- 위에서 언급한 두개의 파일은 모두 실행 속성을 가지고 있어야 한다.
Subversion commit시에 Trac의 티켓에 영향을 미치도록 commit message 작성하기
다음과 같은 동작을 수행할 수 있습니다.
- 티켓 자동으로 닫기
- 티켓에 자동으로 comment 추가하기
# It searches commit messages for text in the form of:
# command #1
# command #1, #2
# command #1 & #2
# command #1 and #2
#
# Instead of the short-hand syntax "#1", "ticket:1" can be used as well, e.g.:
# command ticket:1
# command ticket:1, ticket:2
# command ticket:1 & ticket:2
# command ticket:1 and ticket:2
#
# In addition, the ':' character can be omitted and issue or bug can be used
# instead of ticket.
#
# You can have more then one command in a message. The following commands
# are supported. There is more then one spelling for each command, to make
# this as user-friendly as possible.
#
# close, closed, closes, fix, fixed, fixes
# The specified issue numbers are closed with the contents of this
# commit message being added to it.
# references, refs, addresses, re, see
# The specified issue numbers are left in their current status, but
# the contents of this commit message are added to their notes.
#
# A fairly complicated example of what you can do is with a commit message
# of:
#
# Changed blah and foo to do this or that. Fixes #10 and #12, and refs #12.
#
# This will close #10 and #12, and add a note to #12.
# command #1
# command #1, #2
# command #1 & #2
# command #1 and #2
#
# Instead of the short-hand syntax "#1", "ticket:1" can be used as well, e.g.:
# command ticket:1
# command ticket:1, ticket:2
# command ticket:1 & ticket:2
# command ticket:1 and ticket:2
#
# In addition, the ':' character can be omitted and issue or bug can be used
# instead of ticket.
#
# You can have more then one command in a message. The following commands
# are supported. There is more then one spelling for each command, to make
# this as user-friendly as possible.
#
# close, closed, closes, fix, fixed, fixes
# The specified issue numbers are closed with the contents of this
# commit message being added to it.
# references, refs, addresses, re, see
# The specified issue numbers are left in their current status, but
# the contents of this commit message are added to their notes.
#
# A fairly complicated example of what you can do is with a commit message
# of:
#
# Changed blah and foo to do this or that. Fixes #10 and #12, and refs #12.
#
# This will close #10 and #12, and add a note to #12.
즉, Subversion commit 메시지에 특정 스트링을 넣으면, Trac의 티켓이 자동으로 변경됩니다.
Subversion commit과 함께 5, 10번 티켓을 닫을려면 다음과 같이 사용할 수 있다.
"close" 대신에 "closed", "closes", "fix", "fixed", "fixes" 등을 사용할 수도 있다.
close #5, #10
close #5 & #10
close #5 and #10
close ticket:5, ticket:10
close #5 & #10
close #5 and #10
close ticket:5, ticket:10
Subversion commit과 함께 commit 메시지를 5번, 10번 티켓의 comment로 추가하려면...
"refs" 대신에 "references", "addresses", "re", "see"등을 사용할 수도 있다.
refs #5, #10
refs #5, #10
refs #5 & #10
refs #5 and #10
refs ticket:5, ticket:10
refs #5, #10
refs #5 & #10
refs #5 and #10
refs ticket:5, ticket:10
자. 이제 Subversion에서 commit을 하면, 자동으로 Trac의 관련 티켓이 닫히거나, comment가 추가되게 됩니다.
참고로 말씀 드립니다.
오늘 서점에 갔다가 "윈도우 프로젝트 필수 유틸리티"란 책을 보았습니다.
이 책에 윈도우 환경에서 Subversion과 Trac을 연동하는 방법이 아주 잘 설명되었습니다.
참고하시기 바립니다.
프로그래밍을 작성하다보면 세계 시간을 확인해야할 때가 많습니다.
그런 경우에 사용하면 좋을 것 같은 사이트를 하나 소개해 드리겠습니다.
이 사이트가 제공하는 기능들을 살펴보겠습니다.
시간과 관련된 몇가지 용어를 말씀드리면 다음과 같습니다.
GMT : 영국에 있는 그리니치 천문대에서의 LocalTime입니다. 이 시간은 UTC와 동일합니다.
UTC : 세계 표준 시간입니다. 전 세계 어디에서나 완전히 일치하는 유일한 시간이죠
LocalTime : 각 지역별 시간입니다. 한국은 오전 9시면, 영국은 자정이죠.
DST : Daylight Saving Time 혹은 Summer Time이라고도 합니다.
해가 길때, 시간을 당겨서 활용하는 방법입니다.
각 나라마다, DST를 적용하거나/적용하지 않고, 적용하는 시기도 다 틀립니다.
그리고 DST에 적용되는 시간도 틀리죠.
- 물론 global market을 염두에 두었을때겠죠.
그런 경우에 사용하면 좋을 것 같은 사이트를 하나 소개해 드리겠습니다.
이 사이트가 제공하는 기능들을 살펴보겠습니다.
- 먼저 각 나라/도시별로 현재시간(localtime)을 알려줍니다.
- 물론 해당 지역의 DST(Daylight Saving Time, Summer Time)여부도 알 수가 있습니다.
- 그리고 DST가 언제 시작되고, 언제 끝나는지도 알 수가 있습니다.
- 각 지역의 현재 날씨도 알려줍니다.
시간과 관련된 몇가지 용어를 말씀드리면 다음과 같습니다.
GMT : 영국에 있는 그리니치 천문대에서의 LocalTime입니다. 이 시간은 UTC와 동일합니다.
UTC : 세계 표준 시간입니다. 전 세계 어디에서나 완전히 일치하는 유일한 시간이죠
LocalTime : 각 지역별 시간입니다. 한국은 오전 9시면, 영국은 자정이죠.
DST : Daylight Saving Time 혹은 Summer Time이라고도 합니다.
해가 길때, 시간을 당겨서 활용하는 방법입니다.
각 나라마다, DST를 적용하거나/적용하지 않고, 적용하는 시기도 다 틀립니다.
그리고 DST에 적용되는 시간도 틀리죠.
Subversion과 TortoiseSVN이 1.4 버전이 릴리즈된 이후에 약 2년만에 1.5 버전이 드디어 릴리즈되었습니다.
자세한 릴리즈내용은 다음을 참고하시면 되겠습니다.
* http://subversion.tigris.org/svn_1.5_releasenotes.html
* http://tortoisesvn.tigris.org/tsvn_1.5_releasenotes.html
1.5 버전에서 많은 것이 개선되고, 추가되었습니다.
결론은 1.5 버전을 사용하는 것이 좋겠죠.. ^^;
자세한 릴리즈내용은 다음을 참고하시면 되겠습니다.
* http://subversion.tigris.org/svn_1.5_releasenotes.html
* http://tortoisesvn.tigris.org/tsvn_1.5_releasenotes.html
1.5 버전에서 많은 것이 개선되고, 추가되었습니다.
결론은 1.5 버전을 사용하는 것이 좋겠죠.. ^^;
소스코드 문서화 프로그램 doxygen의 초간단 사용법을 적어볼까 합니다.
doxygen을 사용한 소스코드의 문서화는 다음과 같은 절차로 이루어집니다.
자 그럼 각 단계별로 살펴볼까요.
문서화할 소스코드(C 파일들)가 있다.
기존에 소스코드가 있다면, 문서화할 수 있습니다.
하지만 완벽한 문서화를 위해서는 소스코드에 doxygen이 인식할 수 있도록
주석이 달려있어야만 합니다.
하지만 doxygen용 주석이 달려있지 않아도 문서화된 결과물은 확인할 수 있습니다.
doxygen을 다운로드 받는다.
http://www.stack.nl/~dimitri/doxygen/
doxygen 홈페이지에서 해당 OS에 맞는 설치파일이나 압축 파일을 다운로드 받아서
설치하거나 압축을 풀고 PATH가 연결된 디렉토리에 넣어두면 됩니다.
doxygen용 설정파일을 생성한다.
doxygen용 설정파일의 이름은 특별히 주어지지 않으면 Doxyfile입니다.
기존에 doxygen으로 문서화를 진행하던 프로젝트 혹은 소스코드라면
doxygen용 설정파일인 Doxyfile이 있을 것입니다.
이전 버전의 doxygen용 설정파일을 현재 사용하고 있는 doxygen용 설정파일로 업그레이드하기
기존에 doxygen용 설정파일이 없어서 새롭게 doxygen용 설정파일인 Doxyfile을 만들기
doxygen용 설정파일(Doxyfile)을 내 환경에 맞게 편집한다.
생성된 Doxyfile을 텍스트 편집기로 열어보면
수많은 설정항목들이 있습니다.
(모두 영어로 되어있고, 정말 많습니다. ^^;)
각 항목들은 영어를 이해하시던지, 매뉴얼을 참고하셔야 합니다.
지금은 Doxyfile을 그대로 사용하는 것으로 하죠.
이제 doxygen을 실행해서 소스코드의 문서를 생성합니다.
이제 소스코드에 대한 문서가 생성되었습니다. ^^;
doxygen을 사용한 소스코드의 문서화는 다음과 같은 절차로 이루어집니다.
- 문서화할 소스코드(C 파일들)가 있다
- doxygen을 다운로드 받는다
- doxygen용 설정파일(Doxyfile)을 생성한다.
- doxygen용 설정파일(Doxyfile)을 내 환경에 맞게 편집한다.
- doxygen을 실행한다.
자 그럼 각 단계별로 살펴볼까요.
문서화할 소스코드(C 파일들)가 있다.
기존에 소스코드가 있다면, 문서화할 수 있습니다.
하지만 완벽한 문서화를 위해서는 소스코드에 doxygen이 인식할 수 있도록
주석이 달려있어야만 합니다.
하지만 doxygen용 주석이 달려있지 않아도 문서화된 결과물은 확인할 수 있습니다.
doxygen을 다운로드 받는다.
http://www.stack.nl/~dimitri/doxygen/
doxygen 홈페이지에서 해당 OS에 맞는 설치파일이나 압축 파일을 다운로드 받아서
설치하거나 압축을 풀고 PATH가 연결된 디렉토리에 넣어두면 됩니다.
doxygen용 설정파일을 생성한다.
doxygen용 설정파일의 이름은 특별히 주어지지 않으면 Doxyfile입니다.
기존에 doxygen으로 문서화를 진행하던 프로젝트 혹은 소스코드라면
doxygen용 설정파일인 Doxyfile이 있을 것입니다.
이전 버전의 doxygen용 설정파일을 현재 사용하고 있는 doxygen용 설정파일로 업그레이드하기
doxygen -u [configName]
기존에 doxygen용 설정파일이 없어서 새롭게 doxygen용 설정파일인 Doxyfile을 만들기
doxygen -g [configName]
doxygen용 설정파일(Doxyfile)을 내 환경에 맞게 편집한다.
생성된 Doxyfile을 텍스트 편집기로 열어보면
수많은 설정항목들이 있습니다.
(모두 영어로 되어있고, 정말 많습니다. ^^;)
각 항목들은 영어를 이해하시던지, 매뉴얼을 참고하셔야 합니다.
지금은 Doxyfile을 그대로 사용하는 것으로 하죠.
이제 doxygen을 실행해서 소스코드의 문서를 생성합니다.
doxygen
이제 소스코드에 대한 문서가 생성되었습니다. ^^;
이글의 내용은 Effective C++에서 가져왔습니다.(제 기억이 맞다면요 ^^;)
지금 내가 사용하는 컴파일러가 bool 타입을 지원하지 않는다면
다음과 같은 방법으로 bool 타입을 만들어 사용할 수 있습니다.
열거형 타입으로 bool 타입을 만드는 방법
typedef를 사용해서 bool 타입을 만드는 방법
이제 위에서 언급한 두 가지 방법의 장점과 단점을 보도록 하죠.
열거형 타입으로 bool 타입을 만드는 방법의 장점과 단점
C++에서 함수의 매개변수가 bool 인지 int인지에 따라 함수를 오버로딩할 수 있습니다.
하지만 단점은 비교 연산자는 bool 이 아닌 int를 반환한다는 것입니다.
따라서 열거형으로 정의한 bool을 사용해서 작성된 코드(함수를 오버로딩했을 때)가 나중에 제대로된 bool을 지원하는 컴파일러에서 오동작을 일으킬 수 있습니다.
typedef를 사용해서 bool 타입을 만드는 방법의 장점과 단점
전통적인 C와 C++의 의미구조와 호환이 됩니다.
나중에 bool을 실제 지원하는 컴파일러를 사용해도 열거형을 사용할 때와 같은 문제가 없습니다.
단점은 int와 bool에 대해서 함수 오버로딩을 할 수 없다는 것입니다.
둘중에 어떤 방법을 사용할지는 개발자에게 달려있겠죠.. ^^;
지금 내가 사용하는 컴파일러가 bool 타입을 지원하지 않는다면
다음과 같은 방법으로 bool 타입을 만들어 사용할 수 있습니다.
- 열거형 타입으로 bool 타입을 만드는 방법
- typedef를 사용해서 bool 타입을 만드는 방법
열거형 타입으로 bool 타입을 만드는 방법
typedef enum bool { false, true} bool;
bool b;
b = true;
bool b;
b = true;
typedef를 사용해서 bool 타입을 만드는 방법
typedef int bool;
#define true 1
#define false 0
bool b;
b = true;
#define true 1
#define false 0
bool b;
b = true;
이제 위에서 언급한 두 가지 방법의 장점과 단점을 보도록 하죠.
열거형 타입으로 bool 타입을 만드는 방법의 장점과 단점
C++에서 함수의 매개변수가 bool 인지 int인지에 따라 함수를 오버로딩할 수 있습니다.
하지만 단점은 비교 연산자는 bool 이 아닌 int를 반환한다는 것입니다.
따라서 열거형으로 정의한 bool을 사용해서 작성된 코드(함수를 오버로딩했을 때)가 나중에 제대로된 bool을 지원하는 컴파일러에서 오동작을 일으킬 수 있습니다.
int f(bool);
int f(int);
int a = 3;
f(a); // int f(int)가 호출됩니다.
bool b = true;
f(b); // int f(bool)이 호출됩니다.
f( 3 < 2); // int f(bool)이 아닌 int f(int)가 호출됩니다.
int f(int);
int a = 3;
f(a); // int f(int)가 호출됩니다.
bool b = true;
f(b); // int f(bool)이 호출됩니다.
f( 3 < 2); // int f(bool)이 아닌 int f(int)가 호출됩니다.
typedef를 사용해서 bool 타입을 만드는 방법의 장점과 단점
전통적인 C와 C++의 의미구조와 호환이 됩니다.
나중에 bool을 실제 지원하는 컴파일러를 사용해도 열거형을 사용할 때와 같은 문제가 없습니다.
단점은 int와 bool에 대해서 함수 오버로딩을 할 수 없다는 것입니다.
둘중에 어떤 방법을 사용할지는 개발자에게 달려있겠죠.. ^^;
이전글에서 C와 C++에서의 bool 타입의 동작 대해서 글을 썼습니다.
이제 C언어에서의 bool 타입의 변천사에 대해서 써볼까 합니다.
C99 이전의 C 언어에서는 bool 타입(참과 거짓을 표현하는)이 존재하지 않았습니다.
따라서 프로그래머들은 다음과 같은 방법으로 bool 타입을 사용했습니다.
그러다가 C99에서 드디어 bool 타입이 등장하게 됩니다.
그런데 여기에서 문제가 발생하게 됩니다.
bool, true, false로 구성된 bool 타입을 C99에서 추가하려고 하니까.
기존에 위와 같은 식으로 bool 타입을 만들어서 사용하던 수많은 C 코드들에서
문제가 발생하게 된 겁니다.
그래서 C99에서는 boolean 타입으로 bool을 사용하지 못하고 _Bool을 만들었습니다.
음. 그런데 _Bool 보다는 bool이 보기에도 좋고, 타자수도 적죠.
그래서 C99에서는 stdbool.h 파일을 제공하기로 했습니다.
stdbool.h 파일에는 다음과 같이 bool 이 정의되어있습니다.
그럼 결론은 다음과 같습니다.
이제 C언어에서의 bool 타입의 변천사에 대해서 써볼까 합니다.
C99 이전의 C 언어에서는 bool 타입(참과 거짓을 표현하는)이 존재하지 않았습니다.
따라서 프로그래머들은 다음과 같은 방법으로 bool 타입을 사용했습니다.
typedef int bool
#define false 0
#define true 1
bool b;
b = true;
#define false 0
#define true 1
bool b;
b = true;
그러다가 C99에서 드디어 bool 타입이 등장하게 됩니다.
그런데 여기에서 문제가 발생하게 됩니다.
bool, true, false로 구성된 bool 타입을 C99에서 추가하려고 하니까.
기존에 위와 같은 식으로 bool 타입을 만들어서 사용하던 수많은 C 코드들에서
문제가 발생하게 된 겁니다.
그래서 C99에서는 boolean 타입으로 bool을 사용하지 못하고 _Bool을 만들었습니다.
음. 그런데 _Bool 보다는 bool이 보기에도 좋고, 타자수도 적죠.
그래서 C99에서는 stdbool.h 파일을 제공하기로 했습니다.
stdbool.h 파일에는 다음과 같이 bool 이 정의되어있습니다.
typedef _Bool bool;
#define true (_Bool)1
#define false (_Bool)0
#define true (_Bool)1
#define false (_Bool)0
그럼 결론은 다음과 같습니다.
- C99에서 드디어 C 언어에서도 bool 타입을 제공한다.
- C99에서 제공하는 boolean 타입의 지시어는 bool이 아닌 _Bool이다.
- 만약 C99 표준에서 제공하는 boolean 타입을 _Bool이 아닌 bool을 사용해서 사용하고 싶다면 <stdbool.h> 파일을 include해서 사용한다.
C, C++에서의 bool 타입에 대해서 테스트를 해봤습니다.
테스트한 툴은 각각 다음과 같습니다.
첫번째, bool/BOOL 타입의 사이즈(sizeof)를 테스트해봤습니다.
두번째, int 타입을 bool 타입에 대입해보았습니다.
세번째, bool 타입을 정수(int)와 비교해 보았습니다.
bool 타입을 테스트한 결과는 다음과 같습니다.
gcc-2.95.3의 bool 타입과 VC6과 VS2005의 BOOL 타입은 다음과 같이 구현되어있을 것입니다.
gcc-4.1.2와 g++-4.1.2의 bool 타입과 VC6, VS2005의 bool 타입은
실제 bool 타입으로 볼 수 있습니다.
하지만 gcc의 경우에는 다음과 같은 경우에 어떤 경고도 발생시키지 않습니다.
(혹시 gcc에서 이 경우에 경고를 출력할 수 있는 옵션이 있다면 알려주시면 감사하겠습니다.^^;)
그럼 이제 bool 타입을 어떻게 사용해야할까요?
gcc-2.95.3에서는 bool 타입을 사용하지 말아야겠습니다.
제 개인적으로는 bool 타입의 의미가 더 혼란스러워지는 것 같습니다.
실제 값이 true,false가 아닌 다른 값을 가질 수도 있고,
어떤 경고도 없으니까요
VC6, VS2005에서는 BOOL이 아닌 bool을 사용해야합니다.
BOOL은 int 타입입니다. bool 타입으로 정확하게 동작하는 것은 BOOL이 아닌
bool 입니다. 따라서 BOOL이 아닌 bool 타입을 사용해야 합니다.
bool 타입을 비교하는 경우에 참과 비교하지 말고, 거짓과 비교해야 합니다.
다음의 코드를 보죠.
테스트한 툴은 각각 다음과 같습니다.
- gcc-4.1.2, g++-4.1.2, gcc-2.95.3
- VC6, VS2005
첫번째, bool/BOOL 타입의 사이즈(sizeof)를 테스트해봤습니다.
/* gcc-4.1.2, g++-4.1.2 */
#include <stdbool.h>
printf("sizeof bool : %d\n", sizeof( bool)); // 결과는 1
/* gcc-2.95.3 */
printf("sizeof bool : %d\n", sizeof( bool)); // 결과는 4
/* VC6, VS2005 */
printf("sizeof bool : %d\n", sizeof( bool)); // 결과는 1
printf("sizeof BOOL : %d\n", sizeof( BOOL)); // 결과는 4
#include <stdbool.h>
printf("sizeof bool : %d\n", sizeof( bool)); // 결과는 1
/* gcc-2.95.3 */
printf("sizeof bool : %d\n", sizeof( bool)); // 결과는 4
/* VC6, VS2005 */
printf("sizeof bool : %d\n", sizeof( bool)); // 결과는 1
printf("sizeof BOOL : %d\n", sizeof( BOOL)); // 결과는 4
두번째, int 타입을 bool 타입에 대입해보았습니다.
/* gcc-4.1.2, g++-4.1.2 */
#include <stdbool.h>
bool b;
b = 3; // b는 1의 값을 가지게 됩니다.
b = -3; // b는 1의 값을 가지게 됩니다.
/* 컴파일 옵션은 "-Wall -W"를 사용했습니다.
* int에서 bool 타입으로의 암시적 타입변환에 어떠한 경고도 출력되지 않습니다. */
/* gcc-2.95.3 */
bool b;
b = 3; // b는 3의 값을 가지게 됩니다.
b = -3; // b는 -3의 값을 가지게 됩니다.
/* VC6, VS2005 */
/* 정수값을 bool 타입에 대입할 경우에 경고가 발생하게 됩니다. */
bool b;
b = 3; // b는 1의 값을 가지게 됩니다.
BOOL B;
B = 3; // B는 3의 값을 가지게 됩니다.
#include <stdbool.h>
bool b;
b = 3; // b는 1의 값을 가지게 됩니다.
b = -3; // b는 1의 값을 가지게 됩니다.
/* 컴파일 옵션은 "-Wall -W"를 사용했습니다.
* int에서 bool 타입으로의 암시적 타입변환에 어떠한 경고도 출력되지 않습니다. */
/* gcc-2.95.3 */
bool b;
b = 3; // b는 3의 값을 가지게 됩니다.
b = -3; // b는 -3의 값을 가지게 됩니다.
/* VC6, VS2005 */
/* 정수값을 bool 타입에 대입할 경우에 경고가 발생하게 됩니다. */
bool b;
b = 3; // b는 1의 값을 가지게 됩니다.
BOOL B;
B = 3; // B는 3의 값을 가지게 됩니다.
세번째, bool 타입을 정수(int)와 비교해 보았습니다.
/* gcc-4.1.2, g++-4.1.2 */
#include <stdbool.h>
bool b;
b = 3;
/* int와 bool 타입의 비교에 대해 어떤 경고도 없습니다. */
if( b == 3) {
printf("b is 3\n");
} else {
// b에 3을 대입했지만, 결과는 b는 3과 같지 않습니다.
printf("b is not 3\n");
}
/* gcc-2.95.3 */
bool b;
b = 3;
/* int와 bool 타입의 비교에 대해 어떤 경고도 없습니다. */
if( b == 3) {
// 결과는 b는 3과 같다고 나옵니다.
printf("b is 3\n");
} else {
printf("b is not 3\n");
}
/* VC6, VS2005 */
/* int와 bool 타입의 비교에 대해 경고를 발생시킵니다. */
bool b;
b = 3;
if( b != 3) {
/* b에 3을 대입했지만, 결과는 b는 3과 같지 않습니다. */
printf("b is not 3\n");
}
BOOL B;
B = 3;
if( B == 3) {
/* B에 3을 대입하고, 그 값이 여전히 3입니다. */
printf("B is 3\n");
}
#include <stdbool.h>
bool b;
b = 3;
/* int와 bool 타입의 비교에 대해 어떤 경고도 없습니다. */
if( b == 3) {
printf("b is 3\n");
} else {
// b에 3을 대입했지만, 결과는 b는 3과 같지 않습니다.
printf("b is not 3\n");
}
/* gcc-2.95.3 */
bool b;
b = 3;
/* int와 bool 타입의 비교에 대해 어떤 경고도 없습니다. */
if( b == 3) {
// 결과는 b는 3과 같다고 나옵니다.
printf("b is 3\n");
} else {
printf("b is not 3\n");
}
/* VC6, VS2005 */
/* int와 bool 타입의 비교에 대해 경고를 발생시킵니다. */
bool b;
b = 3;
if( b != 3) {
/* b에 3을 대입했지만, 결과는 b는 3과 같지 않습니다. */
printf("b is not 3\n");
}
BOOL B;
B = 3;
if( B == 3) {
/* B에 3을 대입하고, 그 값이 여전히 3입니다. */
printf("B is 3\n");
}
bool 타입을 테스트한 결과는 다음과 같습니다.
gcc-2.95.3의 bool 타입과 VC6과 VS2005의 BOOL 타입은 다음과 같이 구현되어있을 것입니다.
typedef int bool; // gcc-2.95.3
typedef int BOOL; // VC6, VS2005
typedef int BOOL; // VC6, VS2005
gcc-4.1.2와 g++-4.1.2의 bool 타입과 VC6, VS2005의 bool 타입은
실제 bool 타입으로 볼 수 있습니다.
하지만 gcc의 경우에는 다음과 같은 경우에 어떤 경고도 발생시키지 않습니다.
- int 타입을 bool 타입에 대입
- int 타입과 bool 타입의 비교
(혹시 gcc에서 이 경우에 경고를 출력할 수 있는 옵션이 있다면 알려주시면 감사하겠습니다.^^;)
그럼 이제 bool 타입을 어떻게 사용해야할까요?
gcc-2.95.3에서는 bool 타입을 사용하지 말아야겠습니다.
제 개인적으로는 bool 타입의 의미가 더 혼란스러워지는 것 같습니다.
실제 값이 true,false가 아닌 다른 값을 가질 수도 있고,
어떤 경고도 없으니까요
VC6, VS2005에서는 BOOL이 아닌 bool을 사용해야합니다.
BOOL은 int 타입입니다. bool 타입으로 정확하게 동작하는 것은 BOOL이 아닌
bool 입니다. 따라서 BOOL이 아닌 bool 타입을 사용해야 합니다.
bool 타입을 비교하는 경우에 참과 비교하지 말고, 거짓과 비교해야 합니다.
다음의 코드를 보죠.
BOOL B;
B = 3;
if( B == TRUE) {
/* B는 TRUE가 아닙니다. B는 3의 값을 가지고, TRUE는 1의 값을 가집니다. */
}
위 코드를 다음과 같이 수정해보죠.
다음의 코드들은 모두 위와 같은 문제가 없습니다.
BOOL B;
B = 3;
if( B) {
}
if( !B) {
}
if( B != FALSE) {
}
if( B == FALSE) {
}
B = 3;
if( B == TRUE) {
/* B는 TRUE가 아닙니다. B는 3의 값을 가지고, TRUE는 1의 값을 가집니다. */
}
위 코드를 다음과 같이 수정해보죠.
다음의 코드들은 모두 위와 같은 문제가 없습니다.
BOOL B;
B = 3;
if( B) {
}
if( !B) {
}
if( B != FALSE) {
}
if( B == FALSE) {
}
Subversion의 속성중 가장 많이 사용하고 유용하게 사용하는 속성이
svn:ignore 속성이 아닐까 생각합니다.
svn:ignore 속성을 어떤때 사용하는지 예를 한번 들어보도록 하죠.
리눅스에서 C 프로그램을 작성하고 있다고 한다면 다음과 같은 파일들이 있을 겁니다.
이 중에서 실제 버전 관리되어야 할 파일은 소스파일들과 Makefile뿐입니다.
오브젝트 파일과 실행파일은 버전관리되어서는 안되겠죠.
작업사본(working copy)의 상태를 확인하기 위해서 "svn status" 명령을 실행해보죠
a.o와 a.out 파일이 위와 같이 "?"로 표시되지 않을 수도 있습니다.
(subversion 설정 파일에서 .o 파일이 자동으로 ignore 리스트에 추가되어있다면
위와 같이 a.o와 a.out 파일의 앞에 "?"로 표시되지 않을 것 입니다.)
만약 위와 같은 오브젝트 파일이 수십개가 있다고 생각해보면,
"svn status" 명령을 내릴 때마다, 버전 관리와는 상관없는 오브젝트 파일들을 계속해서 봐야만 합니다.
이럴때 사용하는 것이 svn:ignore 속성입니다.
이 속성의 의미는 여기에 등록된 파일들 및 디렉토리들은 버전관리하지 않는 것이 확실하므로
무시하라는 의미입니다.
그럼 개발환경별로 무시해야될 파일들이 어떤것들이 있는지 알아보죠.
리눅스에서 C 프로그램을 작성한다면 다음과 같은 파일들이 될 것입니다.
윈도우의 VC6 프로젝트라면 다음과 같습니다.
윈도우의 VS2005 프로젝트(VC++)라면 다음과 같습니다.
자! 그럼 이제 실제 속성들을 어떻게 설정하는지를 볼까요.
리눅스의 콘솔이라면 간단합니다.
윈도우에서 콘솔을 사용한다면, 도스 창에서 위명령을 써야겠지요.
아니면 TortoiseSVN을 사용하셔도 됩니다.
svn:ignore 속성이 아닐까 생각합니다.
svn:ignore 속성을 어떤때 사용하는지 예를 한번 들어보도록 하죠.
리눅스에서 C 프로그램을 작성하고 있다고 한다면 다음과 같은 파일들이 있을 겁니다.
- .c, .h 확장자의 소스파일들
- 빌드를 자동(?)으로 수행해줄 Makefile
- .o 확장자의 오브젝트 파일들
- 최종적으로 생성되는 .out 실행파일들
이 중에서 실제 버전 관리되어야 할 파일은 소스파일들과 Makefile뿐입니다.
오브젝트 파일과 실행파일은 버전관리되어서는 안되겠죠.
작업사본(working copy)의 상태를 확인하기 위해서 "svn status" 명령을 실행해보죠
$ svn status
M a.c
M a.h
M Makefile
? a.o
? a.out
M a.c
M a.h
M Makefile
? a.o
? a.out
a.o와 a.out 파일이 위와 같이 "?"로 표시되지 않을 수도 있습니다.
(subversion 설정 파일에서 .o 파일이 자동으로 ignore 리스트에 추가되어있다면
위와 같이 a.o와 a.out 파일의 앞에 "?"로 표시되지 않을 것 입니다.)
만약 위와 같은 오브젝트 파일이 수십개가 있다고 생각해보면,
"svn status" 명령을 내릴 때마다, 버전 관리와는 상관없는 오브젝트 파일들을 계속해서 봐야만 합니다.
이럴때 사용하는 것이 svn:ignore 속성입니다.
이 속성의 의미는 여기에 등록된 파일들 및 디렉토리들은 버전관리하지 않는 것이 확실하므로
무시하라는 의미입니다.
그럼 개발환경별로 무시해야될 파일들이 어떤것들이 있는지 알아보죠.
리눅스에서 C 프로그램을 작성한다면 다음과 같은 파일들이 될 것입니다.
- 오브젝트파일(*.o)
- 디펜던시 파일(*.d 혹은 .depend)
- 최종 실행파일
윈도우의 VC6 프로젝트라면 다음과 같습니다.
- Debug, Release 디렉토리
- *.aps, *.ncb, *.opt, *.plg, *.clw, *.positions, README.TXT
윈도우의 VS2005 프로젝트(VC++)라면 다음과 같습니다.
- Debug, Release 디렉토리
- *.ncb, *.suo, README.TXT 파일들
자! 그럼 이제 실제 속성들을 어떻게 설정하는지를 볼까요.
리눅스의 콘솔이라면 간단합니다.
$ cat ignore.list
*.o
*.d
.depend
*.out
$ svn propset -R svn:ignore -F ignore.list .
혹은 기존에 있던 svn:ignore 속성을 수정하려면
$ svn propedit svn:ignore .
*.o
*.d
.depend
*.out
$ svn propset -R svn:ignore -F ignore.list .
혹은 기존에 있던 svn:ignore 속성을 수정하려면
$ svn propedit svn:ignore .
윈도우에서 콘솔을 사용한다면, 도스 창에서 위명령을 써야겠지요.
아니면 TortoiseSVN을 사용하셔도 됩니다.
이올린에 북마크하기
Prev
Rss Feed