자기 자신을 출력 하는 코드

Posted by 시경이 Study/C++ / C : 2008/10/15 15:19

옛날에 어느 책에서 봤는데 자기 자신을 출력하는 코드가 있었다.
내 기억으로는 상당히 복잡했었는데
인터넷에서 잠깐 검색해본 결과 별거 없었다.ㅡㅡ;;
콰인(quine) 라고 하는 사람의 이름을 따서 지은것으로..
여기 코드에서 중요한점은 단지 하나....
따옴표나 개행문자는 아스키 코드로 나타내야 한다는 점..

#include <stdio.h>
char S[] = "#include <stdio.h>%cchar S[] = %c%s%c;%cint main() { printf(S, 10, 34, S, 34, 10); return 0; }";
int main(){  printf(S, 10, 34, S, 34, 10);  return 0; }

여기서 10은 아스키 코드로 LF 즉 New Line(개행문자)를 의미
35는 따옴표(") 를 의미.

태그 : quine, 콰인

함수 포인터

Posted by 시경이 Study/C++ / C : 2008/09/01 11:36

포인터? 생각만 하면 머리가 아파오는 녀석이죠..C 언어로 생계를 유지해온 저로서도 복잡한 포인터를 보면 피하고 싶습니다..이런 포인터 인데 함수포인터라니? 이건 뭐 대마왕급이군요...

그런데 이런 대마왕도 상황에 따라, 그리고 고급프로그래밍을 위해서 간간히 써주어야만 하는 돌발상황이 발생하곤 합니다..어쩔수 없는 운명이죠..TT

피할수 없다면 한번 부딪혀 보는 건 어떨까요? 기초 개념만 잡으면 너무 쉽다(?)고 느끼실 겁니다..자, 그럼 기본부터 한번 시작해 보겠습니다..

우선 다음과 같은 코드를 보죠..아주 단순한 코드입니다..

main()

{

  int a = 10;

  int* b = &a;

  ...

  ...

}

변수 a 에 10을 대입하고 변수 b 에는 a 의 주소값을 저장합니다. 그럼 여기서 질문하나 해볼까요? 변수 a 와 b 는 어디에 존재할까요? CPU ? 하드디스크 ? 아님 메모리?

모두 아시겠지만 변수는 메모리, 정확히 말하면 RAM 에 존재합니다.

그럼 다음 코드를 한번 보겠습니다..좀전보다 조금 어렵습니다..(???)


void func(int x)

{

  printf("x = %d\n",x);

}


main()

{

  int a = 10;

  int* b = &a;


  func(a);

}

이번에는 함수 func 라는 놈이 등장했네요..여기서 다시 질문하나 할께요..변수는 RAM 에 저장되는데 그럼 함수 func 는 어디에 저장될까요? 또 main 도 특별한 함수죠..즉, 시작할때 제일 먼저 불리는 함수..이런 함수들은 도대체 어디에 존재하는걸까요????

함수는 변수와 마찬가지로 RAM 에 저장되어 있습니다...왜냐면 실행되는 모든 프로그램은 RAM 에 저장되어야 하는데 함수도 프로그램의 일부이니까요..

변수처럼 함수도 RAM 의 어딘가에 func 라는 함수부분이 저장되어 있습니다. RAM에는 언제나 주소가 있죠? 예를 들어 변수 a 는 &a 라는 주소에 있고 변수 b 는 &b 라는 곳에 있습니다. 그럼 func 는 어디에 있을까요?

주소를 나타내려면 & 를 붙인다고 했으니 &func? 아님 임의의 다른곳??

C 언어에서 함수가 저장되어 있는 주소값은 바로 함수 이름입니다. 즉, 함수이름이 함수가 저장되어 있는 첫번째 번지를 나타냅니다. (마치 배열과 비슷합니다. 배열 이름이 배열의 시작주소를 나타내는 것처럼요..) 그래서 func 라는 함수가 저장되어 있는 번지는 func 이고, main 함수가 저장되어 있는 번지는 main 입니다..(많이 헛갈리시죠..예전에 제가 그랬습니다...)

이제 함수가 저장되어 있는 주소값을 알았으니 그 값을 저장할수 있는 변수도 있어야겠죠..이렇듯 함수가 저장되어 있는 주소값을 저장할수 있는 변수를 '함수포인터' 라고 합니다. 즉, 함수포인터는 함수의 이름을 가지는 변수입니다..

그럼 함수이름을 저장할수 있는 변수는 어떻게 선언하고 초기화 할까요? 다음의 소스를 한번 보죠..


void func(int x)

{

  printf("x = %d\n",x);

}


main()

{

  int a = 10;

  int* b = &a;


  void (*test)(int);

  test = func;


  func(a);

}


우선 'void (*test)(int);' 부분입니다. 해석을 해보면 test 라는 변수는 인자로 한개의 정수(-int-) 를 가지고 반환형이 없는 (-void-) 함수를 가리키는 포인터이다 입니다. 이렇게 선언된 test 라는 변수에 func, 즉 func 가 저장되어 있는 주소값(-함수이름-)을 대입하는 곳이 소스에서 'test=func' 입니다. (func 함수가 인자로 정수한개를 받고 반환형은 없죠..확인해보세요)

이제 마지막으로 함수포인터를 통해 함수가 어떻게 호출되는지 알아보겠습니다..소스코드에서 변수 포인터 b 를 통해 a 를 접근하고자 할때 '*b' 라고 기술했습니다. 그럼 함수포인터는 ? 함수포인터도 변수 이므로 *b 처럼 * 연산자를 이용해 함수를 접근할수 있습니다.다음의 코드를 보면서 결과값이 같다는 것을  확인해보시기 바랍니다...코드에서 (*test)(a) 의 해석은 다음과 같다고 할수 있습니다. 'test 라는 변수가 가리키는 곳에다 a 값을 넘겨준다'


void func(int x)

{

  printf("x = %d\n",x);

}


main()

{

  int a = 10;

  int* b = &a;


  void (*test)(int);

  test = func;


  func(a);

  (*test)(a);

}


어떠신가요? 함수포인터라고 무시무시한 이름을 가지고 있지만 막상 별것 없죠..이런 함수포인터는 속도가 중요시되거나 그래픽관련 프로그래밍을 구현하고자 할때 가끔 쓰입니다. 또한 커널 프로그래밍을 할때도요..그러나 기본에 충실하시면 어렵지 않게 이해 할수 있을거라 믿습니다..



출처 :
 [C 프로그래밍] 함수포인터|작성자 악동  (약간의 편집을 했음)

태그 : 함수포인터

콜백함수(Callback function) 이란?

Posted by 시경이 Study/C++ / C : 2008/08/31 13:25

1. A와 B module이 있다.
2. B는 A의 sub이다.
3. B는 A의 구조를 모른다.(즉 시키는대로만 할뿐이다.)

이때, A가 B의 어떤 function을 call했습니다.
그런데, 그 function의 결과값에 따라 A가 어떤 동작을 선택적으로
해야 합니다.

물론 return으로 처리가 가능할수도 있으나, A가 자기 내부 구조는
알리지 않은채 B가 알아서 결과값도 계산해내고, 또 그결과에 의해
A가 해야 할 처리까지도 맡게(책임을 지게) 하고 싶을 경우,
A는 각 동작방식(method)까지를 B에게 함께 알려줍니다.

그러면, B는 처음 A가 지시한 작업(혹은 function call)을 수행하고
그 결과에 따른 A의 동작까지를 책임지고 처리할수가 있습니다.
그렇게 A가 B한테 알려주는 A의 function을 callback이라고 합니다.
역으로 call한다고 해서 그렇게 붙여진 이름입니다.

뭐 이건 아주 단순화시킨 비유긴 하지만, 개념적으론 이렇게 됩니다.

흔히 드는 예가 표준 라이브러리의 qsort입니다. 이 함수는 정렬할 데이터의
형에 제한이 없도록 설계된 함수입니다. 내장형 뿐만 아니라 구조체 같은
사용자 정의형에도 사용이 될 수 있으려면 "어떤 기준으로 정렬할 것인가"가
문제가 됩니다. 이 문제를 콜백을 이용하여 구현합니다.

 typedef struct
    {
        int number;
        const char* name;
    } S;

    int cmp_by_number(const void* p1, const void* p2)
    {
        const S* ps1 = p1;
        const S* ps2 = p2;
        return ps1->number - ps->number;
    }

    int cmp_by_name(const void* p1, const void* p2)
    {
        const S* ps1 = p1;
        const S* ps2 = p2;
        return strcmp(ps1->name, ps2->name);
    }

    S array[10];
    qsort(array, 10, sizeof(S), cmp_by_number); // number 순으로 정렬
    qsort(array, 10, sizeof(S), cmp_by_name);   // name 순으로 정렬


qsort 입장에서는 주어진 데이터를 어떻게 정렬할지 미리 알 수는 없으므로
qsort를 호출하는 쪽에서 "이런 방법으로 정렬하라"는 정보를 콜백을 통해
알려주는 것입니다.

본론으로 돌아와서

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

이런식으로 CALLBACK  을 붙여주는 이유는 단지 가독성(readability) 을 높이기 위함이다.

그리고 무엇을 보고 CALLBACK 를 적였냐고 하면은,

윈도우 클래스 등록시

typedef struct _WNDCLASS {
UINT style;
WNDPROC lpfnWndProc; //WNDPROC A 32-bit pointer to a window procedure.
//요넘이 우리가 코딩할때 등록해 주는 함수포인터가된다..
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;

위에 lpfnWndProc <--- 요것이 함수 포인터 이기때문이다.




출처 : http://kldp.org/node/41169, http://majorss.egloos.com/114372
태그 : callback, 콜백

문자를 숫자로 바꾸는 함수

Posted by 시경이 Study/C++ / C : 2008/08/14 18:19
int atoi(
   const char *str 
);
int _wtoi(
   const wchar_t *str 
);
int _atoi_l(
   const char *str,
   _locale_t locale
);
int _wtoi_l(
   const wchar_t *str,
   _locale_t locale
);










































WCHAR 을 DWORD 로 바꾸려면,
_wtoi 써서 int 로 바꾼뒤 그냥 DWORD 캐스팅 하면 된다.




 
태그 : atoi, wtoi

WINBASEAPI
int
WINAPI
MultiByteToWideChar(
    UINT     CodePage,
    DWORD    dwFlags,
    LPCSTR   lpMultiByteStr,
    int      cchMultiByte,
    LPWSTR   lpWideCharStr,
    int      cchWideChar);


WINBASEAPI
int
WINAPI
WideCharToMultiByte(
    UINT     CodePage,
    DWORD    dwFlags,
    LPCWSTR  lpWideCharStr,
    int      cchWideChar,
    LPSTR    lpMultiByteStr,
    int      cchMultiByte,
    LPCSTR   lpDefaultChar,
    LPBOOL   lpUsedDefaultChar);



void main(void)
{
    char * str = "유니코드";
    WORD wc[8] = L"\0";
    char cTemp[16] = { 0 };

    MultiByteToWideChar( CP_ACP, 0, str, strlen(str)+1, wc, 8 );// char 형 str 을 유니코드로

   WideCharToMultiByte( CP_ACP, 0,  wc,  lstrlenW(wc), cTemp, 16 , 0, 0 );// wc를 cTemp                                                                                      
    printf (" cTemp : %s \n", cTemp);  
}


이거 찾는다고 시끕했다. 간단하게 바뀌는구나 아싸~~

출 처 : http://blog.naver.com/jiyol77?Redirect=Log&logNo=30009840186

char*, LPCTSTR, TCHAR 의 차이

Posted by 시경이 Study/C++ / C : 2008/07/19 00:11

어떠한 문자열을 처리하는 자료형은 보통 char, wchar, TCHAR 를 사용한다.
 
쉽게 보면,
char* => LPSTR 라고 생각하면 되고
const char* => LPCSTR 라고 할 수 있다.
 
가운데 'C' 는 const 의 의미다. 'LP' 는 long pointer 의 의미.
끝에 STR 이라는 의미는 NULL 포인터로 끝난다는 의미. 즉, 마지막 인덱스에는 항상 NULL 이 채워져 있어야 한다는 것.
그래야만 str 관련 함수들이 동작을 하는 것이다. strlen, strcpy, strcmp 등등.. 이것들이 src param 의 끝에 NULL 이 없으면 무지 당황하게 된다.
 
가운데 'T' 가 들어간다는 것은 TCHAR 이라는 의미.
그렇다면 왜 T를 쓸까??
 
영문은 1바이트.

그런데, 우리나라 말이나, 중국어 등 영문권이 아닌 제 3세계 언어를 표현하기 위해서는
2바이트가 필요하다.. 이를 위해서 MultiByte 를 사용하기도 하지만 MultiByte 는
어떤 글씨는 1바이트 이고 어떤 글씨는 2바이트여서 메모리 관리가 어렵다.
그래서 나온 것이 wchar 인데,

wchar 는 모든 글씨(영문 포함)가 2바이트로 구성이 된다.
당연히 wchar 는 일반 ascii 타입의 char 보다 메모리 공간이 2배 필요하다.
 
그런데 본론인 TCHAR 는 무엇이냐?
바로 ACSCII 타입의 일반 char 또는 wchar 라는 의미다.
TCHAR 을 사용하면 char 인지 wchar 인지 구별하지 않고 그냥 코딩을 하면 된다.
 
TCHAR tch = _T('A'); <=> char ch = 'A';
TCHAR tch = _T('A'); <=> wchar wch = 'A';
 
배열도 역시.. 그냥 숫자 인덱스로 원하는 글씨의 위치를 추적할 수 있다.
 
그럼 무엇으로 현재 프로젝트의 TCHAR가 char 인지 wchar 인지를 구별할까?
UNICODE 라는 precompile 상수.
 
해당 프로젝트 project -> settings 에 _DEBUG 등등 선언되어 있는데, 끝에다
UNICODE 라고 쓰고 컴파일 하면 앞으로 나오는 모든 TCHAR 타입은 wchar 으로 변환해서
컴파일을 시도하게 된다.
 
가운데 C 다음의 T 는 TCHAR 이라는 의미
 
당연히 상수로 변환을 했으므로 변수에 값을 대입할 수 없겠다.
( b[3] = _T('A'); <- syntax error  <=> const char str = "ABCD"; str[3] = 'E' ; <- 이때 에러와 같은 이치)
 
(TCHAR 을 나타는 매크로가 _T 이다. (한문자 _T(' '), 문장 _T(" ") )

원문 : http://wooya510.wordpress.com/2006/06/26/char-lpctstr-tchar-%EC%9D%98-%EC%B0%A8%EC%9D%B4/

태그 : char*, LPCTSTR, TCHAR

C/C++ 유니코드

Posted by 시경이 Study/C++ / C : 2008/07/19 00:09

(1) Unicode text 문자열

Windows 98 API 부분적으로 유니코드 문자열을 지원하였다. Windows 2000 NT API 유니코드와 ANSI 문자열을 지원한다. 그러나 Windows CE Unicode 지원한다.

MBCS : Multi-Byte Character String. 특수문자 다음에 나오는 문자는 서로 다른 문자체계의 문자임을 알려 주는 구분자로 사용.

Unicode : Wide byte character 방식. ANSI 문자의 경우 상위 바이트는 NULL 되며, 압축 알고리즘에서는 반복적으로 발생되는 NULL 최적화한다.

 

(2) 일반 문자열과 문자 데이터

유니코드 데이터 형인 wchar_t 사용할 수도 있으나, tchar.h include 시키고, TCHAR 데이터형을 사용하여 definition 따라 char wchar_t형으로 적절히 변환할 있다.

 

#define _UNICODE // TCHAR wchar_t 형으로 대치

#define _MBCS  // TCHAR char 형으로 대치

 

문자열 포인터는 LPSTR 데이터형 대신 LPTSTR 데이터형을 사용하여 definition 따라 char * wchar_t * 형으로 적절히 변환할 있다.

 

(3) 상수문자열

LPTSTR lpszStr = "My string";           // 문자열을 ANSI 문자열로 간주,

                                                     // 데이터형 불일치로 에러 발생

LPTSTR lpszStr = _T("My string");     // _UNICODE 정의되어 있으면 _T() 유니코드

                                                     // 문자열 상수로 변환하고, _MBCS 정의되어 있으면

                                                     // ANSI 문자열 상수로 변환한다.

LPTSTR lpszStr = TEXT("My string"); // 상동

LPWSTR lpszStr = L("My string");      // 유니코트 문자열로 지정하는 매크로 함수 L()


(4) 문자열 버퍼 길이 계산

#define _UNICODE

TCHAR szBuffer[200];                               // szBuffer 크기는 400 bytes

DWORD dwlen;

dwlen = sizeof(szBuffer);                           // 400 bytes

dwlen = sizeof(szBuffer) / sizeof(TCHAR);  // 실제 저장 가능한 유니코드 문자 개수는 200


(5) 표준 문자열 라이브러리 함수

표준 C 런타임 함수 strlen() 해당하는 유니코드 함수는 wcslen()이지만, _tcslen() 사용하면 definition 정의에 따라 컴파일시에 적절히 변환된다.

 

             기능                                ANSI 함수    유니코드 함수   일반 문자열 함수

================================ ============ ============= ==================

문자열의 길이를 반환하는 함수          strlen()        wcslen()         _tcslen()

문자열을 접합하는 함수                strcat()        wcscat()         _tcscat()

문자열에서 문자를 찾는 함수             strchr()        wcschr()        _tcschr()

문자열을 비교하는 함수                strcmp()       wcscmp()       _tcscmp()

문자열을 복사하는 함수                    strcpy()        wcscpy()        _tcscpy()

부분 문자열을 찾는 함수                   strstr()         wcsstr()         _tcsstr()

문자열을 역순으로 저장하는 함수       strrev()        _wcsrev()       _tcsrev()

================================ ============ ============= ==================


(6) ANSI 문자열과 Unicode 문자열 간의 변환

mbstowcs(WCHAR *des, char *src, int BufferSize)  :

Multi-Byte String Wide Character  String(유니코드)으로 변환.

wcstombs(char *des, WCHAR *src, int BufferSize)  :

Wide Character String(유니코드) Multi-Byte String으로 변환.


(7)
ANSI 문자열과 Unicode 문자열 출력 함수
ANSI :      printf           sprintf              scanf
Unicode:  wprintf        swprintf           wscanf
TCHAR :   tprintf          stprintf              tscanf


원글 : http://ryongs.egloos.com/253633
태그 : c, C++

int를 string 으로 변환방법

Posted by 시경이 Study/C++ / C : 2008/07/19 00:00


char
*_itoa( int value, char *string, int radix );

char *_i64toa( __int64 value, char *string, int radix );

char * _ui64toa( unsigned _int64 value, char *string, int radix );

wchar_t * _itow( int value, wchar_t *string, int radix );

wchar_t * _i64tow( __int64 value, wchar_t *string, int radix );

wchar_t * _ui64tow( unsigned __int64 value, wchar_t *string, int radix );
                                                                                        <msdn발췌 >

인자 (parameter)
char *_itoa( int value, char *string, int radix );

value : 문자열로 바뀔 정수값
string : 바뀌는 문자열 결과를 저장할 버퍼
radix : 2진법, 10진법, 16진법 등 정수값이 바뀌게 될때 숫자형식을 지정 (범위 2~36)

리턴 값 (return value)
문자열 포인터를 리턴하며 에러 리턴은 없다.


--------------------------------------------------------------------------------
※ 참 고 : DWORD 를 WCHAR 로 바꾸는 방법은
  
  TCHAR t_Str[100] = { NULL };
   wsprintf(t_Str, L"%d", m_ID);
  // 여기서 m_ID 는 DWORD 형이다.

태그 : 형변환

"deprecated로 선언되었습니다" 의 의미

Posted by 시경이 Study/C++ / C : 2008/07/15 20:53

■ Deprecated


- 포직스 함수들중 몇몇함수들이 visual studio 2005에서 부터 다른 함수들로 바뀌면서 Warning이 뜨게 된다.

   새로 정의 된 함수들로 바꾸어 주라는 의미이다. MS 독자의 길을 가겠다는 의미인지 아니면 예전함수들의 에러나 버그를 고친

   버전이 일 것이다

  

   경고 2 warning C4996: 'sprintf'이(가) deprecated로 선언되었습니다. d:\data\tsource\mfclog\mfclog.cpp 108

   보안(security)을 강화하면서 예전 함수에는 Warning를 띄우나보다. -.-;;
   Warnnig이 떠도 특별히 문제없이 쓸수는 있다고 한다.


 

deprecate :~을 옳지 않다고 역설하다., 계획 따위에 반대하다.

   MS에는 밑에 같이 쓰면 저 Warnning은 표시안다고 했는데 잘 안된다.

  #define _CRT_SECURE_NO_DEPRECATE 1

  밑에 같이 써주면 Warnning이 표시되어지지않는다.

  #pragma warning(disable:4996)

   Warnning이 표시되어지지 않는다고 문제가 해결된 것은 아니고 가장 좋은 것은 MS가 추천하는 함수로 바꾸는 것이 가장 좋을 것 같다.
   Warnning이 뜨는게 먼가 찝찝하면 ctrl+F5을 눌러서 해당 함수를 검색하여 새로 바뀐 함수로 사용하면 말끔히 사라진다.

 
■ Visual Stdio 2005 ( Function )
--------------------------------------------------------------

   http://msdn2.microsoft.com/en-us/library/ms235384(VS.80).aspx

   Run-Time Library Reference 
   Deprecated CRT Functions 

   Deprecated CRT functions and their recommended replacements.

Deprecated POSIX functions

The following POSIX names for functions are deprecated. In most cases, prepending an underscore character gives the standard equivalent name. Note that some functions have more secure versions ("_s" suffix).

You can also eliminate POSIX deprecation warnings by defining _CRT_NONSTDC_NO_DEPRECATE.


Deprecated function Replacement function

access

_access, _access_s

cabs

_cabs

cgets

_cgets, _cgets_s

chdir

_chdir

chmod

_chmod

chsize

_chsize, _chsize_s

close

_close

cprintf

_cprintf, _cprintf_s

cputs

_cputs

creat

_creat

cscanf

_cscanf, _cscanf_s

cwait

_cwait

dup

_dup

dup2

_dup2

ecvt

_ecvt, _ecvt_s

eof

_eof

execl

_execl

execle

_execle

execlp

_execlp

execlpe

_execlpe

execv

_execv

execve

_execve

execvp

_execvp

execvpe

_execvpe

fcloseall

_fcloseall

fcvt

_fcvt, _fcvt_s

fdopen

_fdopen

fgetchar

_fgetchar

filelength

_filelength

fileno

_fileno

flushall

_flushall

fputchar

_fputchar, _fputwchar

gcvt

_gcvt, _gcvt_s

getch

_getch

getche

_getche

getcwd

_getcwd, _wgetcwd

getpid

_getpid

getw

_getw

hypot

_hypot

inp

_inp

inpw

_inpw

isascii

__isascii

isatty

_isatty

iscsym

__iscsym

iscsymf

__iscsymf

itoa

_itoa, _itoa_s

j0

_j0

j1

_j1

jn

_jn

kbhit

_kbhit

lfind

_lfind, _lfind_s

locking

_locking

lsearch

_lsearch, _lsearch_s

lseek

_lseek

ltoa

_ltoa, _ltoa_s

memccpy

_memccpy

memicmp

_memicmp

mkdir

_mkdir

mktemp

_mktemp, _mktemp_s

open

_open

outp

_outp

outpw

_outpw

putch

_putch

putenv

_putenv, _putenv_s

putw

_putw

read

_read

rmdir

_rmdir

rmtmp

_rmtmp

setmode

_setmode

sopen

_sopen, _sopen_s

spawnl

_spawnl

spawnle

_spawnle

spawnlp

_spawnlp

spawnlpe

_spawnlpe

spawnv

_spawnv

spawnve

_spawnve

spawnvp

_spawnvp

spawnvpe

_spawnvpe

strcmpi

_stricmp

strdup

_strdup

stricmp

_stricmp

strlwr

_strlwr, _strlwr_s

strnicmp

_strnicmp

strnset

_strnset, _strnset_s

strrev

_strrev

strset

_strset, _strset_s

strupr

_strupr, _strupr_s

swab

_swab

tell

_tell

tempnam

_tempnam

toascii

__toascii

tzset

_tzset

ultoa

_ultoa, _ultoa_s

umask

_umask, _umask_s

ungetch

_ungetch

unlink

_unlink

wcsdup

_wcsdup

wcsicmp

_wcsicmp

wcsicoll

_wcsicoll

wcslwr

_wcslwr, _wcslwr_s

wcsnicmp

_wcsnicmp

wcsnset

_wcsnset, _wcsnset_s

wcsrev

_wcsrev

wcsset

_wcsset, _wcsset_s

wcsupr

_wcsupr, _wcsupr_s

write

_write

y0

_y0

y1

_y1

yn

_yn

Security-enhanced functions

The following functions should be avoided because a more secure version of the function should be used instead. For more information, see Security Enhancements in the CRT.


Deprecated function Security-enhanced replacement

_alloca

_malloca

asctime

asctime_s

_cgets, _cgetws

_cgets_s, _cgetws_s

_chsize

_chsize_s

_controlfp

_controlfp_s

_creat

_sopen_s

_cscanf

_cscanf_s

_cscanf_l

_cscanf_s_l

ctime

ctime_s

_ctime32

_ctime32_s

_ctime64

_ctime64_s

_cwscanf

_cwscanf_s

_cwscanf_l

_cwscanf_s_l

_ecvt

_ecvt_s

_fcvt

_fcvt_s

fopen

fopen_s

freopen

freopen_s

fscanf

fscanf_s

_fscanf_l

_fscanf_s_l

fwscanf

fwscanf_s

_fwscanf_l

_fwscanf_s_l

_gcvt

_gcvt_s

getenv

getenv_s

gets, _getws

gets_s, _getws_s

gmtime

_gmtime_s

_gmtime32

_gmtime32_s

_gmtime64

_gmtime64_s

_i64toa

_i64toa_s

_i64tow

_i64tow_s

_itoa

_itoa_s

_itow

_itow_s

localtime

_localtime_s

_localtime32

_localtime32_s

_localtime64

_localtime64_s

_ltoa, _ltow

_ltoa_s, _ltow_s

_mbccpy

_mbccpy_s

_mbccpy_l

_mbccpy_s_l

_mbscat

_mbscat_s

_mbscpy

_mbscpy_s

_mbslwr, _mbslwr_l

_mbslwr_s, _mbslwr_s_l

_mbsnbcat, _mbsnbcat_l

_mbsnbcat_s, _mbsnbcat_s_l

_mbsnbcpy, _mbsnbcpy_l

_mbsnbcpy_s, _mbsnbcpy_s_l

_mbsnbset

_mbsnbset_s

_mbsnbset_l

_mbsnbset_s_l

_mbsncat

_mbsncat_s

_mbsncat_l

_mbsncat_s_l

_mbsncpy

_mbsncpy_s

_mbsncpy_l

_mbsncpy_s_l

_mbsnset

_mbsnset_s

_mbsnset_l

_mbsnset_s_l

mbsrtowcs

mbsrtowcs_s

_mbsset

_mbsset_s

_mbsset_l

_mbsset_s_l

_mbstok

_mbstok_s

_mbstok_l

_mbstok_s_l

mbstowcs, _mbstowcs_l

mbstowcs_s, _mbstowcs_s_l

_mbsupr, _mbsupr_l

_mbsupr_s, _mbsupr_s_l

memcpy

memcpy_s

memmove

memmove_s

_mktemp

_mktemp_s

_open

_sopen_s

scanf

scanf_s

_scanf_l

_scanf_s_l

_searchenv

_searchenv_s

setbuf

setvbuf

_snprintf

_snprintf_s

_snprintf_l

_snprintf_s_l

_snscanf

_snscanf_s

_snscanf_l

_snscanf_s_l

_snwprintf

_snwprintf_s

_snwprintf_l

_snwprintf_s_l

_snwscanf

_snwscanf_s

_snwscanf_l

_snwscanf_s_l

_sopen

_sopen_s

_splitpath

_splitpath_s

sprintf

sprintf_s

_sprintf_l

_sprintf_s_l

sscanf

sscanf_s

_sscanf_l

_sscanf_s_l

strcat

strcat_s

strcpy

strcpy_s

_strdate

_strdate_s

strerror, _strerror

strerror_s, _strerror_s

_strlwr, _strlwr_l

_strlwr_s, _strlwr_s_l

strncat, _strncat_l

strncat_s, _strncat_s_l

strncpy, _strncpy_l

strncpy_s, _strncpy_s_l

_strnset

_strnset_s

_strnset_l

_strnset_s_l

_strset

_strset_s

_strset_l

_strset_s_l

_strtime

_strtime_s

strtok

strtok_s

_strtok_l

_strtok_s_l

_strupr, _strupr_l

_strupr_s, _strupr_s_l

swprintf

swprintf_s

_swprintf_l

_swprintf_s_l

swscanf

swscanf_s

_swscanf_l

_swscanf_s_l

tmpfile

tmpfile_s

_ui64toa, _ui64tow

_ui64toa_s, _ui64tow_s

_ultoa, _ultow

_ultoa_s, _ultow_s

_umask

_umask_s

vsnprintf, _vsnprintf, _vsnprintf_l, _vsnwprintf, _vsnwprintf_l

vsnprintf_s, _vsnprintf_s, _vsnprintf_s_l, _vsnwprintf_s, _vsnwprintf_s_l

vsprintf, _vsprintf_l, vswprintf, _vswprintf_l, __vswprintf_l

vsprintf_s, _vsprintf_s_l, vswprintf_s, _vswprintf_s_l

_wasctime

_wasctime_s

_wcreat

_wsopen_s

wcrtomb

wcrtomb_s

wcscat

wcscat_s

wcscpy

wcscpy_s

_wcserror, __wcserror

_wcserror_s, __wcserror_s

_wcslwr, _wcslwr_l

_wcslwr_s, _wcslwr_s_l

wcsncat, wcsncat_l

wcsncat_s, _wcsncat_s_l

_wcsncpy, _wcsncpy_l

wcsncpy_s, _wcsncpy_s_l

_wcsnset, _wcsnset_l

_wcsnset_s, _wcsnset_s_l

wcsrtombs

wcsrtombs_s

_wcsset, _wcsset_l

_wcsset_s_wcsset_s_l

wcstok, _wcstok_l

wcstok_s, _wcstok_s_l

wcstombs, _wcstombs_l

wcstombs_s, _wcstombs_s_l

_wcsupr_l, _wcsupr

_wcsupr_s, _wcsupr_s_l

_wctime, _wctime32, _wctime64

_wctime_s, _wctime32_s, _wctime64_s

wctomb, _wctomb_l

wctomb_s, _wctomb_s_l

_wfopen

_wfopen_s

_wfreopen

_wfreopen_s

_wgetenv

_wgetenv_s

wmemcpy

wmemcpy_s

wmemmove

wmemmove_s

_wmktemp

_wmktemp_s

_wopen

_wsopen_s

_wscanf, _wscanf_l

_wscanf_s, _wscanf_s_l

_wsearchenv

_wsearchenv_s

_wsopen

_wsopen_s

_wsplitpath

_wsplitpath_s

_wstrdate

_wstrdate_s

_wstrtime

_wstrtime_s

Functions with Secure Template Overloads



----------------------------------------------------------
다른 참조할 만한 링크
Security Enhancements in the CRT(C Run-Time Libraries)
 
http://msdn2.microsoft.com/en-us/library/8ef0s5kh(VS.80).aspx

문자열에 관해서...

Posted by 시경이 Study/C++ / C : 2008/07/09 16:12
작성자: Ospace(ospace114@naver.컴)
History
080109 ospace 최초작성

제가 Windows 환경에서 개발하면서 가장 골치아픈 자료형이 문자열이다. 다른 자료형은 정수형과 실수형이고 값의 범위 정도만 알면 충분하다. 같은 형태 자료형이면 공통된 범위에 속한 값이면 쉽게 변환이 가능하고 사용할 수 있다. 그러나 문자열은 다르다. 물론 문자열 자체가 기본 자료형이 아니기 때문에 더욱더 그렇다고 볼 수 있다.

먼저 문자열 자료형의 종류를 살펴보고, 이들간의 변환을 살펴보겠다. 대부분의 내용는 MSDN를 참고했으며, 그외에 나름대로 시행착오로 만들어졌다.

그 다음으로 문자열간의 변환 방법을 알아보겠다.

마지막으로 문자열 관련 팁을 몇가지 넣도록 하겠다.

  • 문자열 자료형의 종류
  • 문자열간 자료형 변환 방법
  • 문자열 관련 팁

Note: 여기서는 자료형에 대해서만 다루며 문자 인코딩/디코딩에 대해서는 다루지 안는다.

문자열 자료형의 종류

char

가장 기본적인 문자 자료형으로 char이 있다. 이를 이용해서 문자열을 표현하는 방식이 가장 일반적이다. 보통 C-style 문자열이라고 한다.

char* str1; // 포인터 문자열로 사용 전에 반드시 메모리 할당하고 다 사용한 후에 해제해야한다.
char str2[256]; // 배열형 문자열

문제점
char은 Ascii 문자를 저장할 수 있는 것으로 영어권 외에 문자저장에는 적합하지 않다.


TCHAR

윈도우에서 가장 일반적인 문자열로서 Win32 API 호출시 많이 사용되는 문자열 형식이다. 물론 많이 보지 못할 수도 있다. 만약 char이용한 문자열 사용한다면 TCHAR로 사용하는 문자열 사용을 강력 추천한다. char을 이용하는 방법과 동일하게 사용하면 된다.

char와 차이점은 없고 wchar에 대한 지원이 매크로를 통해서 가능하게 되었다. 아래에 참고로 TCHAR에 타입 정의를 살펴보면 쉽게 알 수 있다.

#ifdef _UNICODE
#typedef wchar TCHAR
#else
#typedef char TCHAR
#endif

즉 단지 char 혹은 wchar을 TCHAR로 치환해서 사용한다고 보면 된다. 그래서 컴파일 환경에 따라서 아스키만 사용하느냐 유니코드도 지원되는냐를 알아서 결정해준다.
TCHAR에서 파생된 여러 문자열 타입 정의들이 있다. 다음에 그 예이다.

  • WCHAR: wchar을 타입 정의. wchar대신에 WCHAR로 사용한다는 의미
  • LPSTR: char 포인터 문자열. 풀어스면 "char* "가 된다.
  • LPWSTR: 포인터 WCHAR일뿐 풀어쓰면 "WCHAR* " 정도가 된다.
  • LPCWSTR: 상수 LPWSTR이다. 풀어쓰면 "const LPWSTR"가 된다.
  • TCHAR: 현재 언어환경에 따라서 char 혹은 wchar가 되기도 한다.
  • LPTSTR: 포인터형 TCHAR 문자열이다. 즉 "TCHAR* "이 된다.
  • LPCTSTR: 상수 LPTSTR 문자열이다. 즉 "const LPTSTR"이 된다.

이때 일반적인 문자열 대입은 어떻게 할까? 아래와 같이 기존 C-style형태로 하면 될까?

예)
TCHAR str[6] = "abc가나다";

위의 예제는 때에 따라서 잘되기도 하고 안되기도 한다. 문제는 TCHAR가 char형으로 사용되는 경우 한글은 "가나다"글자가 어떻게 입력되는지가 문제이다. 그러면 문자열 값을 넣을 경우 사용하는 문자열 셋 환경에 따르면 어떻게 될지 모른다. 이때 필요한 것이 문자열 값을 위한 매크로이다.

기본적인 메크로는 _T, __T, TEXT, _TEXT, __TEXT가 있다. 모두 같은 의미이다. 자신이 편한걸 아무나 사용하면 된다. 사용하는 방법은 다음과 같다.

예)
TCHAR str[6] = _T("abc가나다");

만약 WCHAR인 문자열인 경우는 현재 문자열 셋이 아스키라고 해도 강제로 문자열 값이 유니코드로 저장되어야 한다. 이때 사용하는 매크로가 L이 있다. 이 매크로는 앞의 매크로와는 틀리게 괄호("()")를 사용하지 안는다.

WCHAR str[6] = L"abc가나다";

Note: 추가로, wchar은 vc환경에 따라서 내부 자료형으로 선언되어 사용하거나 unsigned short 타입으로 사용된다. 그래서 때에 따라서 타입간 호환이 안되는 경우도 있으니 참고하길 바란다.
정확한 타입명은 wchar_t(이하 wchar대신에 wchar_t 명칭을 사용)이며 이에 대한 판단은 strsafe.h파일에 있다. 해당 내용은 다음과 같다.

// strsafe.h 파일 내용
#if !define(_WCHAR_T_DEFINED) && !define(_NATIVE_WCHAR_DEFINE)
typedef unsigned short wchar_t
#define _WCHAR_T_DEFINED
#endif

Caution: 그리고, 앞에서 쉽게 이해하기 위해서 유니코드 환경만 고려했지만 MBCS(Multi-Byte Character Set) 환경도 있다. 이때 매크로에의한 타입 정의가 약간 달라지는 부분이 발생한다. TCHAR가 환경에 따라서 바뀐다고 했는데 MBCS인 경우는 char형으로 사용된다. MBCS은 다국에 지원위한 문자열셋인데 TCHAR가 char형인 것은 약간 이상해질 수 있지만 주의하길 바란다.
나머지 LPTSTR과 LPCTSTR은 TCHAR의 확장이므로 모두 char형을 가지게 된다.


OLECHAR

이 문자열은 앞의 C-style문자열과 같은 형태이다. 단지 자동화 인터페이스에서 자주 사용된다. 이것 역시 타입 정의에 의해서 일반적으로 wchar_t로 사용된다. 일반 아스키 기반인 경우는 "#define OLE2ANSI"해주면 char형을 사용한다. 최근에 다국어를 많이 사용하므로 아스키를 사용할 경우는 거의 없으므로 OLE2ANSI를 거의 사용하지 않은다. C-style과 같은 형태라고 해서 WCHAR대신에 OLECHAR로 사용하는 것은 비추천이다.

  • OLECHAR: 풀어서 쓰면 "wchar_t" 형태
  • LPOLESTR: 풀어서 쓰면 "OLECHAR*" 형태
  • LPCOLESTR: 풀어서 스면 "const OLECHAR*" 형태

앞의 _T, TEXT처럼 OLECHAR에 대입할 문자열 값을 다룰 때 사용할 매크로가 있다. OLESTR이 있다. 사용법은 _T, TEXT 등과 같다.

OLECHAR str[6] = OLECHAR("abc가나다");


BSTR

COM 인터페이스서 사용되는 문자열이다. 이 문자열 타입은 파스칼-style과 C-style의 혼합된 문자열 타입니다. 일반적으로 C-style에서는 문자열 끝을 표시할 때에 제로바이트("/0")가 사용된다. BSTR에서는 문자열 시작 전에 문자열 길이(바이트 단위)를 저장하고 그 다음에 문자열 값들이 온다. 물론 문자열 끝에는 종결 문자인 제로 바이트("/0")가 온다. 문자열 길이에는 종결문자가 포함되지 안는다.
이렇게 문자열 앞에 문자열 길이가 오는 것은 COM특성상 다른 곳으로 마샬링해서 데이터를 보낼때 데이터의 크기를 알아야할 필요성이 있다. 이를 위한 정보로 제공된다.

BSTR도 매크로에 의해서 다음과 같이 타입 정의가 되었다.

typedef OLECHAR* BSTR;

조금 이상하다. OLECHAR로 BSTR이 선언되었다. 즉 wchar_t형 문자열이라 볼 수 있다. 그리고 OLECHAR를 포인터로 사용했는데 LPOLESTR로 사용하지 않은 이유는 무엇일까?
BSTR대신에 LPOLESTR로 사용해도 컴파일에는 문제가 없다. 그러나 BSTR 문자열을 받는 함수에서 문자열 값 앞에 길이 정보가 포함되어있다고 가정하에 사용되므로 잘못된 데이터로 처리될 수 있다. 그리고 COM에서 마샬링으로 데이터 전달하는 경우 잘못된 길이의 데이터가 전송될 수 있다.
즉 BSTR타입은 따로 정의해두고 사용하는게 타입 사용에 안전하다.

BSTR은 저장되는 데이터 포멧이 다르므로 그 사용법도 C-style과는 다르다. 이를 위해 제공되는 중요한 함수 두가지가 있다. 즉 문자열 할당과 할당된 문자열 해제하는 함수이다. 간단한 예를 보면 쉽게 이해할 수 있다.

BSTR bstr = NULL;
bstr = SysAllocString(L"abc가나다"); // 문자열 할당

if(bstr == NULL) {
  // BSTR 문자열 할당 실폐
}

// 문자열 처리

SysFreeString(bstr); // 문자열 해제

사용하기가 조금 번거롭다. 그렇다고 이렇게만 사용해야 하는가? 물론 아니다. 역시 똑똑한 사람들이 우리를 위해서 도우미 클래스(Wrapper class)가 있다. (주의: 도우미 함수는 본인이 임의로 붙였다. 정확한 명칭은 랩퍼클래스라고 한다.)


_bstr_t

BSTR 문자열을 다루기 위한 랩퍼 클래스이다. 저장된 문자열 내부에 직접 접근하는 방법은 없다. 그럼 먼저 실제 사용방법을 보자.

// BSTR 문자열 생성
_bstr_t bstr1 = "abc"; // LPCSTR 문자열에서 생성
_bstr_t bstr2 = L"abc가나다"; // LPCWSTR 문자열에서 생성
_bstr_t bstr3 = bstr1; // 다른 _bstr_r에서 생성, 단순 대입처럼 보면 됨

_variant_t  v = "test";
_bstr_t bstr4 = v;  // _variant_t에서 생성

// 원하는 자료형으로 문자열 추출
LPCSTR str1 = bstr1;
LPCSTR str2 = (LPCSTR) bstr1;
LPCWSTR str3 = bstr1;
LPCWSTR str4 = (LPCWSTR) bstr1;
BSTR bstr = bstr1.copy(); //복사
SysFreeString(bstr);  // 앞에서 BSTR사용한 것 처럼 반드시 해제해줘야 한다.

한가지 유념할 점이 있다. 지금 추출되는 문자열이 모두 상수형이다. 즉 내부에 저장된 문자열 포인터를 리턴해준다. 물론 상수형을 제거해서 문자열을 수정할 수 있다. 만약 이렇게 되면 수정된 문자열 길이와 기존에 문자열 길이가 다르게 되는 문제점이 발생하면서 오류가 발생할 수 있다.


CString

앞에는 일반적인 문자를 나열하는 정도로만 보면된다. 지금 부터는 이른 문자열 데이터를 감싸고 있는 클래스 들을 보겠다.

그중에서 대표적인 것이 CString 클래스로 MFC의 대표적인 클래스이다. CString은 TCHAR형 타입을 다룬다. 상당히 방대한 클래스이며 Windows 내부에 사용되는 대부분의 문자열을 처리할 수 있다. 즉 유니코드나 MBSC도 한번에 처리할 수 있다. 그러나 MFC에 종속적이라서 MFC를 사용하지 않고 개발하는 경우 사용할 수 없다. 그리고 문자열 다루기는 쉬우나 메모리 관리 효율성과 성능적인 측면에서는 떨어지는 점이 있다. 이는 본인의 경험에 의한 것이기에 환경이나 조건에 따라서 달라질 수 있겠다.


std::string, std::wsting

템플릿 라이브러리(STL)에서 제공되는 클래스이다. 이는 원래 basic_string에서 기반을 하며 보통 char형 문자열을 저장한다. 그러면 wchar_t형 문자열을 저장할 경우는 wstring을 사용한다.







문자열 포멧이 같은 형태라면 문제가 없으나 앞에서 보았듯이 전혀 다른 포멧을 가지는 경우가 있다. 이때에는 전혀 다른 문자열 값이 된다.

예) (LPCWSTR) "C:\\foo.txt"

CString에서는 다르다. 내부적인 형변환 연자사를 이용해서 형변환을 하게된다.

예)
CString str("C:\\foo.txt");
Fun((LPCTSTR) str); //이때 (LPCTSTR)은 CString 내부에 정의된 형변환 연산자이다.

태그 : 문자열
 «이전 1 2  다음»