2008. 11. 16. 12:07

main 함수의 정확한 선언

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);



명령행 데이타를 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]);
}




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]);
    }
}

 * 이 테스트 프로그램을 위 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.

* 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.

2008. 6. 25. 21:55

세계 시간 확인하기

프로그래밍을 작성하다보면 세계 시간을 확인해야할 때가 많습니다.
  • 물론 global market을 염두에 두었을때겠죠.


그런 경우에 사용하면 좋을 것 같은 사이트를 하나 소개해 드리겠습니다.


이 사이트가 제공하는 기능들을 살펴보겠습니다.
  • 먼저 각 나라/도시별로 현재시간(localtime)을 알려줍니다.
  • 물론 해당 지역의 DST(Daylight Saving Time, Summer Time)여부도 알 수가 있습니다.
  • 그리고 DST가 언제 시작되고, 언제 끝나는지도 알 수가 있습니다.
  • 각 지역의 현재 날씨도 알려줍니다.

시간과 관련된 몇가지 용어를 말씀드리면 다음과 같습니다.
GMT : 영국에 있는 그리니치 천문대에서의 LocalTime입니다. 이 시간은 UTC와 동일합니다.

UTC : 세계 표준 시간입니다. 전 세계 어디에서나 완전히 일치하는 유일한 시간이죠

LocalTime : 각 지역별 시간입니다. 한국은 오전 9시면, 영국은 자정이죠.

DST : Daylight Saving Time 혹은 Summer Time이라고도 합니다.
해가 길때, 시간을 당겨서 활용하는 방법입니다.
각 나라마다, DST를 적용하거나/적용하지 않고, 적용하는 시기도 다 틀립니다.
그리고 DST에 적용되는 시간도 틀리죠.
2008. 5. 16. 20:17

bool 타입을 지원하지 않는 컴파일러에서 bool 타입 사용하기

이글의 내용은 Effective C++에서 가져왔습니다.(제 기억이 맞다면요 ^^;)


지금 내가 사용하는 컴파일러가 bool 타입을 지원하지 않는다면

다음과 같은 방법으로 bool 타입을 만들어 사용할 수 있습니다.

  • 열거형 타입으로 bool 타입을 만드는 방법
  • typedef를 사용해서 bool 타입을 만드는 방법


열거형 타입으로 bool 타입을 만드는 방법
typedef enum bool { false, true} bool;

bool b;
b = true;


typedef를 사용해서 bool 타입을 만드는 방법
typedef int bool;
#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)가 호출됩니다.



typedef를 사용해서 bool 타입을 만드는 방법의 장점과 단점
전통적인 C와 C++의 의미구조와 호환이 됩니다.
나중에 bool을 실제 지원하는 컴파일러를 사용해도 열거형을 사용할 때와 같은 문제가 없습니다.
단점은 int와 bool에 대해서 함수 오버로딩을 할 수 없다는 것입니다.


둘중에 어떤 방법을 사용할지는 개발자에게 달려있겠죠.. ^^;
2008. 5. 16. 19:57

C 언어에서의 bool 타입

이전글에서 C와 C++에서의 bool 타입의 동작 대해서 글을 썼습니다.


이제 C언어에서의 bool 타입의 변천사에 대해서 써볼까 합니다.

C99 이전의 C 언어에서는 bool 타입(참과 거짓을 표현하는)이 존재하지 않았습니다.

따라서 프로그래머들은 다음과 같은 방법으로 bool 타입을 사용했습니다.
typedef int bool
#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


그럼 결론은 다음과 같습니다.
  • C99에서 드디어 C 언어에서도 bool 타입을 제공한다.
  • C99에서 제공하는 boolean 타입의 지시어는 bool이 아닌 _Bool이다.
  • 만약 C99 표준에서 제공하는 boolean 타입을 _Bool이 아닌 bool을 사용해서 사용하고 싶다면 <stdbool.h> 파일을 include해서 사용한다.
2008. 5. 16. 19:36

C, C++ 에서의 불(bool, boolean) 타입의 동작에 대해서

C, C++에서의 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




두번째, 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의 값을 가지게 됩니다.



세번째, 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");
}



bool 타입을 테스트한 결과는 다음과 같습니다.

gcc-2.95.3의 bool 타입과 VC6과 VS2005의 BOOL 타입은 다음과 같이 구현되어있을 것입니다.

typedef int bool;    // gcc-2.95.3
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) {
}