Search

'Program C/C++'에 해당되는 글 6건

  1. 2013.05.10 Class 내부 Thread basic... 1
  2. 2011.09.26 typedef...
  3. 2011.06.24 c 표준 함수들
  4. 2010.10.13 문자열 타입 변환 | C & C++

Class 내부 Thread basic...

Program C/C++ 2013. 5. 10. 16:09 Posted by HisPark

class MyClass
{
   
static DWORD WINAPI StaticThreadStart(void* Param)
   
{
       
MyClass* This = (MyClass*) Param;
       
return This->ThreadStart();
   
}

    DWORD
ThreadStart(void)
   
{
       
// Do stuff
   
}

   
void startMyThread()
   
{
       DWORD
ThreadID;
      
CreateThread(NULL, 0, StaticThreadStart, (void*) this, 0, &ThreadID);
   
}
};

'Program C/C++' 카테고리의 다른 글

typedef...  (0) 2011.09.26
c 표준 함수들  (0) 2011.06.24
문자열 타입 변환 | C & C++  (0) 2010.10.13
C++의 다양한 string 타입 | C & C++  (0) 2010.01.30
About String  (0) 2005.08.05

typedef...

Program C/C++ 2011. 9. 26. 15:12 Posted by HisPark

먼저 typedef struct 지시어에 대해 먼저 논해보자.

<typedef>

typedef unsigned int UINT

// 구문은 unsigned int 자료형을 UINT 쓰겠다는 의미임

.

.

unsigned int i;

UINT i;

//위의 선언을 같은 결과를 가져온다.

함수 포인터의 재정의로도 사용된다.

typedef int (*funcptr) ();

//funcptr 리턴값이 int이고,매개인자가 없는 함수포인터로 선언

.

.

funcptr myfunction[10];

int (*myfunction[10])();

//같은 결과를 가져옴..

<struct>

struct MY_struct {

int a;

int b;

};

//구조체 선언을 나타내는 지시어 struct, MY_struct 구조체의 이름.

// a, b 멤버 데이터이며, 이를 묶어주는 중괄호로 구성되며, 구조체 선언끝에 ; 명시

함수의 선언에서 {} 의미는 메인메모리로 부터 스택영역을 할당받는 역할을 수행하지만, 구조체 선언에서 사용되는 {} 메인메모리에 아무런 영향을 미치지 않는다. 따라서 후자를 구분하기 위해 ; 구조체 선언끝에 명시한다.

구조체의 객체 생성은 다음과 같다.

1.

struct MY_struct {

int a;

int b;

};

struct MY_struct A1, *pA2;

//C compiler에서는 객체 생성시 struct지시어를 반드시 명기해야 하고, C++ compiler에서는 생략해도 C++ complier 알아서 My_struct 사용자 정의 데이터형으로 인식하여 객체를 선언해줌.

//좀더 자세히 설명하면, C complier 변수선언이 가능한 키워드(int , char , float ,void )로만 시작할때 변수선언이 가능합니다. 사용자 정의 변수형(enum, union, struct) 경우 그냥 선언한 이름만 사용할 경우 컴파일러는 변수 선언을 인식하지 못한다. 따라서 C complier에게 사용자 정의 변수형이라는 것을 알려주기 위해 사용자 정의 변수형 이름앞에 지시어를 적어줘야 .

// 구조체의 객체중 A1 정적 객체로 선언, pA2 포인터 객체로 선언.

2.

struct MY_struct {

int a;

int b;

}A1, *pA2;

이상으로 간단하게 typedef struct 지시어에 대해 간단히 알아보았다.

그럼 이제 본격적으로 typedef struct 같이 사용할때의 경우를 알아보자.

앞에서도 언급했지만, 사용자 정의 데이터형을 선언할때 매번 지시어(enum, struct, union) 적어주는 일은 많이 번거롭다. C complier에서는 사용자 정의 타입 이름도 typedef 재정의가 가능하게 허용하였다.

typedef 사용하여 재정의한 사용자 정의 데이터형의 예를 보면,.....

typedef struct __MY_struct{

int a;

int b;

}MY_struct, *pMY_struct;

// 구문에서 __MY_struct 구조체의 이름, a, b 맴버 데이터, MY_struct *pMY_struct 선언한 구조체를 정의한 데이형을 MY_struct *pMY_struct 제선언.

.

.

1.

struct __MY_struct A1, *pA2;

2.

MY_struct A1;

pMY_struct pA2;

//1에서 선언한 것과 2에서 선언한 것은 같은 결과를 가져온다.

//2처럼 사용할 경우 앞에 struct라는 지시어를 사용하지 않고 바로 사용 가능

//보통 C에서는 이런식으로 사용하기 때문에 구조체의 이름은 사용하지 않는 이름으로 정의하고 재정의되는 이름을 알아보기 편한 이름으로 정의한다.

참고적으로, 위에서 선언한 경우는 정석적인 사용이며, 오사용및 변칙사용의 예를 들어 들어 보면....

1.
typedef struct {
int a;
int b;
}MY;


2.
struct MY{
int a;
int b;
};

3.

typedef struct MY{
int a;
int b;
};

1 2 경우는 C++ 에서는 같은 동작을 합니다. 하지만, C에서는 다름 결과를 냅니다.

1에서는 이름없는 구조체가 생성이 되고, 구조체를 사용하기 위한 새로운 자료형이름으로 MY 등록이 됩니다.

2에서는 단지 MY라는 구조체가 생성이됩니다.

따라서 C에서는 다음과 같이 사용해야 합니다.

<1 경우>

MY A1;

<2 경우>

struct MY A1;

3 경우는 에러 발생(경우에 따라서는 warning 뜬다고 합니다.) 사용자의 의도와는 다른 방향으로 컴파일 됩니다.

typedef 경우는 두개의 인자가 필요합니다. 앞의 인자는 컴파일러가 기존에 알고있는 지시어, 뒤에있는 인자는 사용자가 새롭게 정의할 이름입니다.

3 경우는 2번째 인자가 없는 형태이므로 에러가 발생하거나, 그냥 구조체의 이름이 MY 구조체만 생성하게 됩니다.

-이상-

[출처]typedef & struct|작성자kri7001

1. typedef 키워드

- 구조체는 분명히 자료형 입니다.

하지만 우리는 평소에 구조체를 선언해 struct ~~~~ , struct ~~~~ 계속 적어주었습니다.

int자료형은 int 적어주면 되는데, 구조체는 struct 줘야 하는 걸까요?

이럴 경우 소스에 오타가 발생할 경우가 생기고,

또한 귀찮기도 하고, 가독성에도 약간의 문제가 생깁니다.

따라서 struct 없애 있는 키워드가 바로 typedef키워드입니다.

typedef 기본형은 이렇습니다.

typedef double DOUBLE

이것이 무엇을 의미하는 것이냐면

double이라는 자료형에게 DOUBLE이라는 새로운 이름을 지어주는 것입니다.

컴파일러에 실제로 DOUBLE 보시면 double자료형으로 인식하지 못함을 있는데요.

문구만 적어주면 DOUBLE double자료형으로 인식하게 만들어 있습니다.

DOUBLE i=90.2;

따위의 선언이 가능하다는 말이지요.

쉽게 말해서 '컴파일러야~! 이것을~(double) 이것으로(DOUBLE) 생각하려무나(typedef)'

정리해 있습니다.

정말 완벽한 문장이네요.

[만약에 일반공부처럼 C언어공부도 개념정리노트를 만든다고 한다면

문장은 별표 3 붙이고 색깔 분류해놓고 적어놓고 싶네요.]

문장에서 정의한 것을 토대로 한번 구조체도 이런 형식으로 만들어 보겠습니다.

typedefstruct pointer pointer;

'컴파일러야~! struct pointer pointer 생각하려무나'

사용할 있겠습니다.

또한 방법 외에도

typedef struct pointer

{

int i ......

int z.......

}pointer;

형식으로도 제시해 있습니다.

[출처][베리군의C강좌] 19. 구조체 - (5) struct를 지워보자.|작성자베리군

typedef struct 쓰는 이유는

자료명 사용의 용이성(?) 이라고 볼수 있죠

예를 들어 struct card 만들었을경우 구조형을 쓸때마다

struct card 라고 해줘야 하는 반면

이것을 typedef struct card {..... } CARD 선언했을경우

CARD 라고만 해주면 되기 때문이죠

언어 표준만을 지원하는 컴파일러는 위와 같은 구문은 컴파일시 에러나 워닝을 냅니다. 그래서 그와 같은 컴파일러에서는 구조체를 typedef 타입이름으로 선언하더라도, 임시로 사용할 태그 이름이 필요하게 됩니다. 따라서, 이와 같은 컴파일러에서는 다음과 같이 임시 태그 이름을 사용하여 typedef 타입 이름을 선언해야 합니다. (물론, 번거롭긴 하지만 표준과 일치하는 방법입니다.)

typedef struct _tagPoint{
int x;
int y;
}POINT;

이와 같은 구문은, 어떤 컴파일러를 쓰더라도 정확히 동일한 결과를 내므로 안전한 기법이라고 있겠습니다.

'Program C/C++' 카테고리의 다른 글

Class 내부 Thread basic...  (1) 2013.05.10
c 표준 함수들  (0) 2011.06.24
문자열 타입 변환 | C &amp; C++  (0) 2010.10.13
C++의 다양한 string 타입 | C &amp; C++  (0) 2010.01.30
About String  (0) 2005.08.05

c 표준 함수들

Program C/C++ 2011. 6. 24. 14:04 Posted by HisPark


1. 수학 함수

  • 표준 함수 : 함수의 신뢰성과 이식성을 위해 자주 사용되는 함수들을 미리 만들어서 컴파일러와 함께 배포하는 함수로써 이 함수들을 집합을 런타임 라이브러리(CRT)라고 함
     분류  함수
     입출력 함수  printf, scanf, gets, puts, getch, putch
     수학 함수  sin, cos, tan, pow, floor, ceil, hypot
     문자열 함수  strcpy, strlen, strcat, strstr, strchr
     시간 함수  time, asctime, clock
     파일 입출력 함수  fopen, fclose, fseek, fread, fwrite
     프로그램 제어  exit, abort, system
     메모리 할당  malloc, free, realloc, calloc
     기타  rand, delay

 

  • 삼각 함수
     함수  설명
     double sin(double x);  sin 기본 함수
     double cos(double x);  cos 기본 함수
     double tan(doueble x);  tan 기본 함수
     double asin(doueble x);  sin 역함수
     double acos(doueble x);  cos 역함수
     double atan(doueble x);  tan 역함수
     double sinh(doueble x);  sin 쌍곡선 함수
     double cosh(doueble x);  cos 쌍곡선 함수
     double tanh(doueble x);  tan 쌍곡선 함수
    • 수학 함수는 math.h 헤더 파일을 포함 시켜야 사용 가능
    • 실수형 호도(라디안)값을 인수로 받아 실수형 값을 리턴
    • 수학적 삼각 함수의 정의
      • 기하학적 정의 : 각C가 직각인 삼각형ABC에서 각A, B, C와 마주보는 변을 a, b, h라 할 때
        • 사인(Sine) 함수 : sin A = a/h
        • 코사인(Cosine) 함수 : cos A = b/h
        • 탄젠트(Tangent) 함수 : tan A = a/b
        • 코시컨트(Cosecant) 함수 : csc A = h/a = 1/sin A
        • 시컨트(Secant) 함수 : sec A = h/b = 1/cos A
        • 코탄젠트(Cotanget) 함수 : cot A = b/a = 1/tan A
      • 단위원 정의 : 좌표평면에서 원점을 중심으로 반지름의 길이가 1인 원을 단위원이라 하며, 이 단위원 위의 점(x, y)에 대해 x축과 점과 원점을 잇는 각을 라디안r 이라 할 때
        • 사인 함수 : sin r = y
        • 코사인 함수 : cos r = x
        • 탄젠트 함수 : tan r = sin r/cos r
        • 코시컨트 함수 : csc r = 1/sin r
        • 시컨트 함수 : sec r = 1/cos r
        • 코탄젠트 함수 : cot r = cos r/sin r

 

  • 지수 함수
     함수  설명
     double sqrt(double x);  x의 제곱근(√x)
     double pow(double x, double y);  x^y, x의 y승
     double log(double x);  자연 대수(밑이 자연로그 e)
     double log10(double x);  상용 대수(밑이 10)
     double exp(double x);  자연 대수 exp
     double hypot(double x, double y);  직삼각형의 사변 길이(√x^2+y^2)
    • 실수형 값을 인수로 받아 실수형 값을 리턴

 

  • 정수화 함수
     함수  설명
     double floor(double x);  인수보다 크지 않은 최대 정수
     double ceil(double x);  인수보다 작지 않은 최소 정수
    • 응용
      • 소수부 버리기 : 정수형 변수에 대입하면 하강 변환으로 소수부가 버려짐 ( 예 : int i=d;, int i=(int)d )
      • 반올림
        • 기본 : floor(x+0.5)
        • 반올림 자리수 설정 : floor(x*pow(10, dig)+0.5)/pow(10, dig);

 

  • 절대값 함수
     함수  설명
     int abs(int n);  정수형 절대값
     long labs(long n);  실수형 절대값
     double fabs(double x);  실수형 절대값
    • 응용
      • 삼항 조건 연산자를 이용한 절대값 구하기 : (a>0) ? a : -a
      • 어떤 값이 특정 범위에 있는지 검사하기
        • if((a==10) || (a==-10)) -> if(abs(a)==10)
        • if((a==10) || (a==20)) -> if(abs(15-a)==5)
        • if((a>10) && (a<50) -> if(abs(a-30)<20)

 

2. 난수 함수

  • 표준 난수 함수
     함수  설명
     int rand(void);  난수 생성
     void srand(usigned int seed);  난수 발생 시작점(Seed) 제어
    • 컴파일러에 따라 다르지만 일반적으로 0 - 32767 범위 내의 임의의 정수를 생성
    • 난수 함수는 일정한 순서로 난수를 생성
    • 시작점을 바꾸면 생성되는 난수도 바뀌지만, 같은 시작점으로 난수 함수를 연속 호출하면 일정한 순서로 난수를 생성
    • 응용
      • 예측 불가능한 난수 발생 시작점 만들기 : srand((unsigned)time(NULL));
      • 범위 내 난수 생성
        • 0 - 50 : rand() % 51
        • -10 - 10 : (rand() % 21) - 10
        • 0 - 100 사이의 짝수 : (rand() % (100/2)) * 2
        • 0 - 100 사이의 홀수 : (rand() % (100/2)) * 2 + 1
        • 0.0 - 10.0 사이의 실수 : (rand() % 100) / 10.0

 

3. 시간 함수

  • 시간 체계
    • 평균태양시 : 태양이 평균각속도적도상을 움직이는 평균태양을 가정하여 이 시각으로 나타내는 시각을 뜻함

     

    • GMT(Greenwich Mean Time, 그리니치 표준(평균)시)
      • 런던 교외의 그리니치에 설립한 그리니치 천문대를 지나는 자오선본초자오선으로 지정하고, 경도의 원점(기준점)으로 하는 평균태양시
      • 1925년 이전의 GMT는 정오를 0시로 하여 시간을 재기 시작하는 방식의 천문학용 평균태양시
      • 일상생활에서는 자정을 0시로 하여 시간을 재는 방식을 사용하며, 이를 GCT(Greenwich Civil Time, 그리니치 세계(상용)시)라고 함
      • 1925년 1월 1일 GMT를 12시간 앞당겨 GCT와 일치시켰으며, UT(Universal Time, 세계시)라고 하여 전세계 공통의 표준시로 사용
      • GMT와 GCT 모두 그리니치시 라고도 함

     

    • 윤초(Leap Second)
      • 세슘원자시계의 1초 길이와 평균태양시의 1초 길이가 달라 오차가 발생함
      • 오차를 0.9초 이내로 유지하기 위해 1초를 가감하는 것
      • 양의 윤초(Positive Leap Second) : 지구의 자전이 느려져 표준시에 1초를 더하는 것
      • 음의 윤초(Negative Leap Second) : 지구의 자전이 빨라져 표준시에서 1초를 빼는 것
      • 윤초 시행일
        • 지정일 0시 0분 0초 직전에 윤초를 실시하도록 지정된 일자
        • 제 1 우선일 : 1월 1일과 7월 1일에 윤초를 실시
        • 제 2 우선일 : 4월 1일과 10월 1일에 윤초를 실시

     

    • UTC(Universal Time Coordinated, 협정 세계시)
      • 1967년 세슘원자의 주기적인 원자진동이 오차가 3000년에 1초 정도로 매우 정확한 것을 이용하여 세슘원자시계를 국제표준시계로 채택
      • 1972년 1월 1일부터 윤초를 시행하여 세슘원자시계를 평균태양시에 맞춰 UTC로 사용함

     

    • 일광절약시간(Daylight Saving Time, 영국에서는 British Summer Time 또는 Summer Time)
      • 여름철에 표준시보다 1시간 시계를 앞당겨 놓는 제도
      • 일을 일찍 시작하고 일찍 잠에 들어 등화를 절약하고, 일광을 장시간 쪼이게 되어 건강도 증진하기 위한 취지에서 개발됨
      • 현재 한국에서는 실시하지 않고 있으며, 전 세계적으로 약 70여개국이 이 제도를 시행 중임

     

    • 지역 시간(Local Time)
      • 경도의 차이에 따라 GMT나 UTC에 시간을 가감하는 것과 일광절약시간의 시행 유무에 따른 시간차를 합한 각 나라의 시간
      • 한국은 UTC나 GMT에 9시간을 더하고 일광절약시간을 시행하지 않는 KST(Korea Standard Time, 한국 표준시)를 사용하고 있음

 

  • 시간 함수
    • 시간 함수는 time.h 헤더 파일을 포함 시켜야 사용 가능

 

  • time 함수
    • 함수 원형 : time_t time(time_t *timer);
    • 1970년 1월 1일 00시 00분 00초 이후 경과한 초를 조사하는 함수
    • 2038년 1월 18일까지 표현 가능하며, 64비트용 _time64 함수는 3000년 12월 31일까지 표현 가능
    • UTC 포맷으로 되어 있음
    • time_t형의 포인터를 인수로 받아 조사된 시간을 변수에 입력하거나 리턴함
    • time_t형은 시스템에 따라 달라지며 윈도우즈에서는 4바이트 정수형으로 정의되어 있음
    • 응용
      • 리턴값만 전달하여 변수에 조사된 시간을 입력 : time_t now; now=time(NULL);
      • 변수에 직접 조사된 시간을 입력 : time_t now; time(&now);

 

  • ctime 함수
    • 함수 원형 : char *ctime(const time_t *timer);
    • time_t형의 경과초를 문자열 형태로 변환하는 함수
    • 26문자 길이로 되어있으며 끝에 개행문자가 있음
    • UTC + Local Time 포맷으로 되어 있음
    • 버퍼 공유
      • 변환 결과를 저장하기 위해 라이브러리에서 미리 할당된 정적 메모리 영역(버퍼)를 사용함
      • asctime, gmtime, localtime 등의 함수들과 공유함
      • 다른 함수를 사용하게 되면 이전 변환 결과가 파괴됨
      • 버퍼 공유 설계는 C 라이브러리 함수를 만들 때 멀티 스레드가 없었기 때문에 문제가 됨

 

  • _strdate 함수
    • 함수 원형 : char *_strdate(char *datestr);
    • time_t형의 경과초에서 날짜를 MM/DD/YY 포맷으로 구하여 datestr 버퍼에 복사

 

  • _strtime 함수
    • 함수 원형 : char *_strtime(char *timestr);
    • time_t형의 경과초에서 시간을 HH:MM:SS 포맷으로 구하여 timestr 버퍼에 복사

 

  • 시간 구조체
     멤버  설명
     tm_sec  초(0~59)
     tm_min  분(0~59)
     tm_hour  시간(0~23)
     tm_mday  날짜(1~31)
     tm_mon  월(0~11)
     tm_year  1990년 이후 경과 년수
     tm_wday  요일(0~6), 0 : 일요일
     tm_yday  년중 날짜(0~365)
     tm_isdst  일광 절약 시간과의 차

 

  • gmtime 함수
    • 함수 원형 : struct tm *gmtime(const time_t *timer);
    • time_t형의 값을 UTC 포맷의 tm 구조체로 변환함

 

  • localtime 함수
    • 함수 원형 : struct tm *localtime(const time_t *timer);
    • time_t형의 값을 UTC+Local Time 포맷의 tm 구조체로 변환함

 

  • mktime 함수
    • 함수 원형 : time_t mktime(struct tm *timeptr);
    • tm 구조체의 값을 time_t형으로 변환함

 

  • asctime 함수
    • 함수 원형 : char *asctime(const struct tm *timeptr);
    • tm 구조체의 경과초를 문자열 형태로 변환하는 함수(ctime과 동일)
    • UTC 포맷 : time_t형의 값을 gmtime 함수로 tm 구조체로 변환
    • UTC+Local Time : time_t형의 값을 localtime 함수로 tm 구조체로 변환

 

  • strftime 함수
     인수  설명
     char *strDest  버퍼
     size_t maxsize  버퍼의 길이
     const char *format  포맷팅 방식
     const struct tm *timeptr  tm 구조체
    • 함수 원형 : size_t strftime(char *strDest, size_t maxsize, const char *format, const struct tm *timeptr);
    • 포맷팅 방식을 임의로 설정할 수 있음

[Flag - strftime Formatting Code]

 플래그  설명
 %a  Abbreviated weekday name
 %A  Full weekday name
 %b  Abbreviated month name
 %B  Full month name
 %c  Date and time representation appropriate for locale
 %d  Day of month as decimal number (01 – 31)
 %H  Hour in 24-hour format (00 – 23)
 %I  Hour in 12-hour format (01 – 12)
 %j  Day of year as decimal number (001 – 366)
 %m  Month as decimal number (01 – 12)
 %M  Minute as decimal number (00 – 59)
 %p  Current locale's A.M./P.M. indicator for 12-hour clock
 %s  Second as decimal number (00 – 59)
 %U  Week of year as decimal number, with Sunday as first day of week (00 – 53)
 %w  Weekday as decimal number (0 – 6; Sunday is 0)
 %W  Week of year as decimal number, with Monday as first day of week (00 – 53)
 %x  Date representation for current locale
 %X  Time representation for current locale
 %y  Year without century, as decimal number (00 – 99)
 %Y  Year with century, as decimal number
 %z

 the time-zone name or time zone abbreviation, depending on registry settings;

 no characters if time zone is unknown

 %Z

 the time-zone name or time zone abbreviation, depending on registry settings;

 no characters if time zone is unknown

 %%  Percent sign
# 플래그는 모든 포맷팅 코드 앞에 올 수 있으며, 기능은 아래와 같음
 포맷팅 코드  기능

 %#a, %#A, %#b, %#B, %#p, %#X, %#z, %#Z,

 %#%

 # flag is ignored
 %#c

 Long date and time representation, appropriate for current locale

 For example: "Tuesday, March 14, 1995, 12:41:29"

 %#x

 Long date representation, appropriate to current locale

 For example: "Tuesday, March 14, 1995"

 %#d, %#H, %#I, %#j, %#m, %#M, %#S, %#U,

 %#w, %#W, %#y, %#Y

 Remove leading zeros (if any)

 

  • clock 함수
    • 함수 원형 : clock_t clock(void);
    • 프로그램 실행 후의 경과초를 조사하는 함수

 

  • difftime 함수
    • 함수 원형 : double difftime(time_t timer1, time_t timer0);
    • 두 시간의 차이를 조사하는 함수

 

  • 실습
     TimeFunction

     #include <stdio.h>

     #include <time.h>
     //--------------------------------------------------
     //08-3-다.기타 시간 함수
     //각종 시간 함수 실습
     //--------------------------------------------------

     void TimeFunction()
     {
         time_t time1;
     
         //time 함수(UTC) : 리턴값만 전달하여 변수에 조사된 시간을 입력하는 방법
         time1=time(NULL);
         printf("1970년 1월 1일 00:00:00 이후 경과초 : %I64d초\n", time1);

     

         //time 함수(UTC) : 변수에 직접 조사된 시간을 입력하는 방법
         time(&time1);
         printf("1970년 1월 1일 00:00:00 이후 경과초 : %I64d초\n", time1);

     

         //time 함수(UTC) : 변수없이 조사된 시간을 출력하는 방법
         printf("1970년 1월 1일 00:00:00 이후 경과초 : %I64d초\n", time(NULL));

     

         //time 함수(UTC) : ctime 함수와의 차이를 알아보기 위해 경과초를 나눔
         printf("현재 : %I64d시 %I64d분 %I64d초\n", time1/60/60%24, time1/60%60, time1%60);

     

         //ctime 함수(UTC + Local Time) : 개행 문자 포함
         printf("현재 : %s", ctime(&time1));
     
         //_strdate 함수
         char date1[10];
         _strdate(date1);
         printf("현재 : %s\n", date1);

     

         //_strtime 함수(UTC + Local Time)
         char time2[10];
         _strtime(time2);
         printf("현재 : %s\n", time2);

     

         //gmtime 함수(UTC)
         tm *timeptr1;
         timeptr1=gmtime(&time1);
         printf("현재 : %d년 %d월 %d일 %d시 %d분 %d초\n",
              timeptr1->tm_year+1990,/*1990년 이후 경과년수이기 때문에 1990년을 더함*/
              timeptr1->tm_mon+1,/*0월~11월이기 때문에 1을 더함*/
              timeptr1->tm_mday,
              timeptr1->tm_hour,
              timeptr1->tm_min,
              timeptr1->tm_sec);

     

         //localtime 함수(UTC + Local Time)
         timeptr1=localtime(&time1);
         printf("현재 : %d년 %d월 %d일 %d시 %d분 %d초\n",
              timeptr1->tm_year+1990,/*1990년 이후 경과년수이기 때문에 1990년을 더함*/
              timeptr1->tm_mon+1,/*0월~11월이기 때문에 1을 더함*/
              timeptr1->tm_mday,
              timeptr1->tm_hour,
              timeptr1->tm_min,
              timeptr1->tm_sec);
     }

'Program C/C++' 카테고리의 다른 글

Class 내부 Thread basic...  (1) 2013.05.10
typedef...  (0) 2011.09.26
문자열 타입 변환 | C &amp; C++  (0) 2010.10.13
C++의 다양한 string 타입 | C &amp; C++  (0) 2010.01.30
About String  (0) 2005.08.05

문자열 타입 변환 | C &amp; C++

Program C/C++ 2010. 10. 13. 12:53 Posted by HisPark


이 문서에서는 문자셋 간의 변환에 대해서 살펴보도록 하겠습니다. 문자열 타입 변환 이라하면 단순히 char와 wchar_t간의 변환이라고 생각하기 쉬운데 문자셋이란 개념을 꼭 생각하셔야 합니다.


잊지 말아야 할 것
아래 적어둔 것은 자주 헷갈리는 것입니다. 먼저 아래것들을 확실히 해둡시다.

MBCS는 한가지 인코딩이 아니다.
MBCS를 담는 자료형은 char다
UTF-8도 MBCS와 같은 char에 저장한다.
Wide Char는 한가지 인코딩 방식이다. (컴파일러에 따라 UTF-16이거나 UTF-32)
Wide Char는 wchar_t에 담는다.
다시 말하면 wchar_t에는 UTF-16이나 UTF-32로 인코딩 된 문자열만 담긴다.

결국 데이타 타입 관점에서 보면 아래 세가지 케이스가 있다고 할 수 있습니다.

char -> wchar_t
char에 어떤것이 들어 있는지 말해주어야 합니다. 한글이 들어있는 CP949 일수도 있고 일본어가 들어 있는 CP932 등일수도 있습니다. 또 UTF-8일 수도 있습니다.

wchar_t -> char
wide_char를 어떤 인코딩으로 바꿔서 char에 넣을지 정해 주어야 합니다. 역시 위와 마찬가지로 UTF-8, CP949, CP932, 기타 등등이 가능합니다.

char -> char
이런 경우는 두 가지 밖에 없습니다. MBCS를 UTF-8로 바꾸거나 반대의 경우거나.
왜 이 두 가지인지는 MBCS에대해 이해하고 있다면 당연하게 여기실 겁니다.



외부 라이브러리를 이용하는 방법
가장 믿음직하고 다양한 변환이 가능하지만 외부 라이브러리를 설치해야 한다는 압박이 있습니다. 대표적으로 iconv가 있는데 기본적으로 dll을 사용하는 방식으로 되어 있습니다. qt의 qstring을 이용하는 방법도 있다고 하는데 설치하는게 만만찬다고 합니다. 약간의 트릭으로 boost 라이브러리를 사용하는 방법이 있는데 관련 내용은 CPP.log 님의 블로그를 참고하세요. 리눅스에서 iconv없이 개발하고자 할 때 유용할 것 같습니다.



codecvt이용한 변환
쉽지는 않지만 STL의 codecvt를 이용하시면 standard한 인코딩 컨버전 함수를 만들 수 있습니다. 이 방법의 장점은 standard라는데 있습니다. 모든 OS에서 컴파일이 가능합니다. 하지만 실행시점에서 모든 OS가 정상적인 동작을 보장하지 않는 다는 치명적인 단점이 있습니다.
아래는 CPP.log 님의 블로그 에서 가져온 소스입니다. 블로그로 가시면 반대로 변환하는 함수도 보실 수 있습니다. std::locale에 원하는 인코딩을 정해 주실 수 있습니다. 이 때 위에 잊지 말아야 할 것에서 1번을 기억하셔야 합니다. MBCS는 한가지 인코딩이 아니기 때문에 변환할 인코딩을 선택해 주어야 합니다. 아무것도 안적으면 시스템에서 사용하는 문자셋이 설정됩니다.


std::string wcs_to_mbs(std::wstring const& str, std::locale const& loc = std::locale())
{
    typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_t;
    codecvt_t const& codecvt = std::use_facet<codecvt_t>(loc);
    std::mbstate_t state = std::mbstate_t();
    std::vector<char> buf((str.size() + 1) * codecvt.max_length());
    wchar_t const* in_next = str.c_str();
    char* out_next = &buf[0];
    std::codecvt_base::result r = codecvt.out(state,
        str.c_str(), str.c_str() + str.size(), in_next,
        &buf[0], &buf[0] + buf.size(), out_next);
    if (r == std::codecvt_base::error)
       throw std::runtime_error("can't convert wstring to string");  
    return std::string(&buf[0]);
}



만약 위의 함수에 locale을 "ko_KR.UTF-8"로 설정하면 wstring을 UTF-8로 변환하실 수 있습니다. 하지만 locale은 OS의 특성을 탑니다. OS별로 동작 할 수도 안할 수도 있다는 이야기 입니다. 리눅스 계열의 몇몇 OS에서는 잘 돌겠지만 Windows 에서는 확실히 동작하지 않습니다. 해결방법은 외부 라이브러리를 사용하거나 직접 구현하는 수밖에 없습니다.



MultiByteToWideChar를 이용한 변환
MultiByteToWideChar()함수와 WideCharToMuliByte()함수를 사용해서 인코딩을 변환해 주는 것도 가능합니다. 이 두함수는 윈도우에서만 지원합니다. 따라서 OS 디펜던시가 없는 라이브러라 같은 것을 개발하신다면 이 두함수는 사용하실 수 없긴 하지만 많은 윈도우 개발자들이 사랑하는 함수죠.

먼저 MBCS를 UTF-16으로 바꾸는 함수입니다.


int MultiByteToWideChar(
  UINT CodePage,         // 원본 스트링의 현재 인코딩 상태
  DWORD dwFlags,         // 0을 쓰면 된다.
  LPCSTR lpMultiByteStr, // 변환하려는 문자열
  int cbMultiByte,       // -1을 넣으면 lpMultiByteStr의 길이를 알아서 계산
  LPWSTR lpWideCharStr,  // 변환된 유니코드를 저장할 공간
  int cchWideChar        // 유니코드를 저장할 공간의 사이즈
);

첫번째 인자에는 CP_ACP나 UTF-8둘중 하나를 넣으시면 됩니다.

CP_ACP : 시스템에서 사용하는 MBCS -> UTF-16
UTF-8 : UTF-8 -> UTF16
기타 코드 페이지
이함수는 특이한 기능이 있는데 맨마지막 인자에 0을 넣으면 필요한 wchar_t의 공간을 리턴합니다. 이를 이용해서 변환된 문자열에 딱맞는 공간을 할당 하실 수 있습니다. 다음은 반대로 UTF-16을 MBCS로 바꾸는 함수입니다.


int WideCharToMultiByte(
  UINT CodePage,           // 변환 타겟 인코딩
  DWORD dwFlags,           // 0
  LPCWSTR lpWideCharStr,   // 원본 스트링
  int cchWideChar,         // -1을 넣으면 원본 스트링 길이가 자동할당
  LPSTR lpMultiByteStr,    // 목적지
  int cbMultiByte,         // 목적지 사이즈
  LPCSTR lpDefaultChar,    // 실패시 사용
  LPBOOL lpUsedDefaultChar // 실패 여부 판단
);

MultiByteToWideChar()함수와 거의 같은데 인자가 두개더 있습니다. lpDefaultChar인자는 인코딩이 실패했을 때 실패한 문자열 대신 사용될 문자열입니다. 보통 NULL로 지정하시면 됩니다. 마지막 인자 lpUsedDefaultChar는 변환에 실패한 문자가 하나라도 있을 때 TRUE를 리턴합니다. 유니코드는 MBCS보다 사이즈가 큰 집합이기 떄문에 MBCS에서 유니코드로의 변환은 실패할 일이 없지만 반대는 실패할 수도 있음을 기억하셔야 합니다.



USE_CONVERSION 를 이용해 변환
이 매크로를 이용하면 아주 쉽게 문자열을 변환할 수 있습니다. 사용법은 아래와 같습니다.


#include <atlconv.h> // 필요 include
#pragma comment(lib, "atls.lib") // 필요 lib


void SomeFunction()
{
    USES_CONVERSION; // 먼저 적으셔야 합니다.
    
    CAtlStringW wideStr[]=L"abc가나다";
    CAtlStringA ansiStr;
    ansiStr = W2A(widechar);  // UTF-16을 MBCS로 바꿉니다.
}

W2A말고도 여러 매크로를 제공하는데요. 아래와 같습니다. (const 변환용 매크로 제외)
매크로 설명
A2W LPCSTR -> LPWSTR
W2A LPCWSTR -> LPSTR
A2T LPCSTR -> LPTSTR
T2A LPCTSTR -> LPSTR
T2OLE LPCTSTR -> LPOLESTR
OLE2T LPCOLESTR -> LPCSTR

이 매크로는 사용하기엔 편하지만 UTF8을 UTF-16 으로 변환하는데 쓰실 수 없습니다. 또 주의 해야 할 것이 있는데요. 각 매크로를 사용할 떄 변환에 필요한 공간이 스택에 할당된다는 점입니다. 따라서 실제적으로 아래를 주의 하셔야 합니다.

너무 큰 스트링을 변환하고 시도하면 스택 오버 플로가 날 수 있습니다.
루프 안에서 과도한 변환을 시도하면 스택 오버 플로가 날 수 있습니다.
스택에서 잡힌 공간이기 때문에 매크로의 결과를 리턴시키면 안됩니다.



CA2W계열의 클래스를 이용한 변환
USE_CONVERSION 를 이용한 변환이 편하긴 한데 위에서 말한대로 문제가 좀 있기 때문에 ATL 7.0이후 CATW계열의 클래스들이 새로 등장했습니다. 이 아이는 클래스인데다가 기본적으로 128바이트의 내부 버퍼를 가지고 있고(변경 가능 합니다만..), 이보다 크면 알아서 힙에 동적할당을 해주는 똑똑한 놈입니다.


#include <atlconv.h> // 필요 include
#pragma comment(lib, "atls.lib") // 필요 lib


void SomeFunction()
{
        CA2W p ("123가나다");    // 클래스 선언
        CA2WEX<256> p2 ("123마바사");    // EX를 붙이면 내부 버퍼 사이즈를
                                         // 변경시킬 수 있습니다만 새로운
                                         // 사이즈별로 코드가 새로 생깁니다.


        CAtlStringW str(p);      // p가 LPWSTR을 리턴합니다.
        CAtlStringW str2 = p2;   // p2가 LPWSTR을 리턴합니다.
}

이런식으로 사용합니다. 주의할 점은 역시 위 코드에서 보이는 p를 리턴 시키면 안됩니다.(당연한 이야기지만) CA2W외 그밖의 클래스 들은 아래와 같습니다. (아래 목록은 cosnt와 버퍼 사이즈를 변경할 수 있는 EX가 붙어 있는 것들이 제외 되었습니다.)
클래스 설명
CA2W LPCSTR -> LPWSTR
CW2A LPCWSTR -> LPSTR
CA2T LPCSTR -> LPTSTR
CT2A LPCTSTR -> LPSTR
CT2OLE LPCTSTR -> LPOLESTR
COLE2T LPCOLESTR -> LPCSTR
아쉬운 것이 있다면 UTF-8로의 변환을 지원하는 클래스가 있었다면 좀더 좋았을 텐데 이점이 조금 아쉽습니다.


참조 사이트: http://killrain.net
[출처] 문자열 타입 변환 (차니의 컴퓨터 마을) |작성자 newchany

'Program C/C++' 카테고리의 다른 글

Class 내부 Thread basic...  (1) 2013.05.10
typedef...  (0) 2011.09.26
c 표준 함수들  (0) 2011.06.24
C++의 다양한 string 타입 | C &amp; C++  (0) 2010.01.30
About String  (0) 2005.08.05