336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

변수값 음수화는 보통 양수값 앞에 -를 붙이거나 -1 을 곱하는데

문득 속도 차이가 얼마나 날지 궁금해서 테스트를 해보았다.


#include <iostream>
using namespace std;
#include <windows.h>

 

int main()
{
     int testCount = 1000000000;

 

     int x = 10000;
     int y = 0;

     DWORD startTime = 0;
     DWORD endTime = 0;

 

     startTime = GetTickCount();
     for( int i = 0; i < testCount; ++i )
     {
          y = -x;
     }
     endTime = GetTickCount();
     cout << "Test 1 : " << endTime - startTime << endl;

 

     startTime = GetTickCount();
     for( int i = 0; i < testCount; ++i )
     {
          y = x * -1;
     }
     endTime = GetTickCount();
     cout << "Test 2 : " << endTime - startTime << endl;

 

     return 0;
}

 

<결과>

Test 1 : 3422

Test 2 : 3500


그냥 -를 붙이는게 빨랐다

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

URLDownloadToFile example  (0) 2015.05.26
GetCurrentDirectory() vs GetModuleFileName()  (0) 2015.05.22
This program might not have installed correctly  (0) 2015.02.07
문자열 _T("")와 L""  (0) 2015.02.07
레지스트리의 값 가져오기  (0) 2015.02.07
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

설치프로그램 등을 직접 만드는 경우, 파일명에 setup 등과 같은 이름이 들어가면,
종료 후 다음과 같은 경고창이 뜰 수 있습니다. (Vista / Win7 이상)


파일명이 qqqq.exe 라고 하더라도 발생하였습니다.
이런 정책은 Windows OS 마다 변경될 수 있기 때문에, 명확한 대응법으로 막아야 합니다.
물론, 해당 실행파일이 코드 사이닝 되어도 마찬가지 입니다.

해결법은,
2009/09/22 - [프로그래밍/Win32] - .exe에 Manifest 추가
를 참고하면 됩니다.


첨부파일을 \res\add_manifest.xml로 복사합니다.

그리고,


와 같이 프로젝트 세팅을 진행하면 해당 문제는 발생하지 않습니다.
원인등은 검색해 보세요. 여기는 그냥 해결법만 제시합니다.


출처 : http://greenfishblog.tistory.com/113

참고 : http://stackoverflow.com/questions/1069135/this-program-might-not-have-installed-correctly-message-in-windows-7-rc/1069269#1069269

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

GetCurrentDirectory() vs GetModuleFileName()  (0) 2015.05.22
빠른 음수화  (0) 2015.02.07
문자열 _T("")와 L""  (0) 2015.02.07
레지스트리의 값 가져오기  (0) 2015.02.07
# 과 ##  (0) 2015.02.07
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

_T 매크로는

 

_T("문자열") 이라고 썼을때

 

_UNICODE가 define 되어 있으면 L"문자열" 을 리턴하고


define되어있지 않으면 그냥 "문자열" 을 리턴 합니다.

 

문자열 앞에 L 접두사가 붙으면 그 문자열은 유니코드 형태로 인식 되는겁니다.

 

만일 tchar.h전에 _UNICODE 가 define 되면 다음과 같이 정의됩니다.


자세히 하면


#define __T(x) L##x 


즉 __T("Melong") 은 L"Melong" 으로 치환되게 됩니다.


정의되어 있지 않으면 다음과 같이


#define __T(x) x


네, __T("x") 는 그냥 "x" 입니다.


그리고 다음과 같이 또 define 되어 있죠


#define _T(x) __T(x)

#define _TEXT(x) __T(x)


_T 대신 _TEXT라고 써도 됩니다.


L"Melong"이 황당하시죠? 이것은 C++ 문법으로 확장 문자열을 뜻합니다.


다음과 같이 확장문자열 포인터를 지정할 수 있죠


wchar_t *p = L"Melong!";


쉽게 여러 언어를 지원하는 프로그램을 만들기 위해 쓰는 것이다 라고 생각하세요.


출처 : http://blog.naver.com/PostView.nhn?blogId=monkeies&logNo=20101792106

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

빠른 음수화  (0) 2015.02.07
This program might not have installed correctly  (0) 2015.02.07
레지스트리의 값 가져오기  (0) 2015.02.07
# 과 ##  (0) 2015.02.07
strncpy 와 strncpy_s 에 대한 오해  (0) 2015.02.07
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

#include <iostream>

using namespace std;

#include <atlbase.h> // add


int main()

{

HKEY hKey;

TCHAR szDefaultPath[MAX_PATH] = { 0, };

DWORD dwBufLen = MAX_PATH;


RegOpenKeyEx( HKEY_CURRENT_USER, L"Software\\DAUM\\PotPlayer", 0, KEY_READ, &hKey );

RegQueryValueEx( hKey, L"ProgramPath", NULL, NULL, (LPBYTE)szDefaultPath, &dwBufLen );

RegCloseKey( hKey );


return 0;

}


이렇게 하면 szDefaultPath 변수에 HKEY_CURRENT_USER\Software\DAUM\PotPlayer 경로의 ProgramPath 값을 받아올 수 있다.

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

This program might not have installed correctly  (0) 2015.02.07
문자열 _T("")와 L""  (0) 2015.02.07
# 과 ##  (0) 2015.02.07
strncpy 와 strncpy_s 에 대한 오해  (0) 2015.02.07
함수 포인터 typedef  (0) 2015.02.07
Posted by 역시인생한방
,

# 과 ##

Programming/C / C++ 2015. 2. 7. 19:49
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

#과 ##은 전처리기의 연산자로서 컴파일러가 #define 전처리 과정에서만 사용하는 특수한 연산자이다. C 언어 자체의 연산자는 아니므로 우선 순위나 결합 규칙 등은 적용되지 않는다. 둘 다 사용 빈도가 높지는 않지만 잘 알아 두면 매크로의 활용도를 높여 반복되는 코드를 간단하게 작성할 수 있어 작업 효율 향상을 꾀할 수 있다.

# 연산자(stringizing operator)는 #define문의 인수 앞에 사용되며 피연산자를 문자열로 바꾸는 역할을 한다. 피연산자가 실인수로 치환된 후 양쪽에 따옴표를 붙여 치환된 결과 그대로 문자열 상수가 된다. 다음 예제가 이 연산자를 사용하는 가장 전형적인 예제이다.

 

  : SharpOp

#include <Turboc.h>

 

#define result(exp) printf(#exp"=%d\n",exp);

 

void main()

{

     result(5*3);

     result(2*(3+1));

}

 

result 매크로는 인수로 전달된 수식을 printf 함수로 출력하되 수식 자체와 수식의 평가 결과를 같이 출력한다. 실행 결과는 다음과 같다.

 

5*3=15

2*(3+1)=8

 

result(5*3) 호출문은 전처리기에 의해 다음과 같이 치환된다.

 

result(5*3)

 

printf(#5*3"=%d",(5*3)); 인수 치환

 

printf("5*3""=%d",(5*3)); # 다음의 인수가 문자열이 됨

 

printf("5*3=%d",(5*3));   인접한 문자열을 합침

 

매크로로 전달된 5*3 수식이 # 연산자에 의해 문자열로 치환되며 인접한 문자열은 합쳐지므로 5*3이라는 수식 자체가 printf의 서식 문자열의 일부가 된다. 만약 다음과 같이 매크로의 인수 자체를 문자열 내에서 직접 쓰게 되면 이 실인수는 치환되지 않고 exp라고만 출력될 뿐 호출부의 실제 수식이 출력되지 않을 것이다.

 

#define result(exp) printf("exp=%d\n",exp);

 

요컨데 #연산자는 문자열 상수 내부의 형식 인수를 실인수로 치환시킬 때 사용하는 연산자라고 할 수 있다. #연산자는 정확한 문자열 변환을 위해 몇 가지 규칙을 적용하는데 상식 수준에서 쉽게 이해되는 규칙들이다. #과 형식 인수 사이의 공백, 형식 인수 다음의 공백은 무시되므로 #exp, # exp는 동일하다. 실인수내의 공백은 하나만 인정되며 둘 이상의 공백은 하나만 남기고 모두 삭제된다. 실인수내에 주석이 있으면 이 주석은 하나의 공백으로 대체된다.

 

호출부

치환 결과

result(5*3)

5*3=15

result(5 * 3)

5 * 3=15

result(5* 3)

5* 3=15

result(5     *     3)

5 * 3=15

result(5*/*곱하기*/3);

5* 3=15

 

실인수에 겹따옴표나 역슬레쉬 등 확장열로 처리해야 할 문자가 있다면 이 문자 앞에 확장열 선두 문자인 \가 자동으로 삽입된다. #define println(msg) printf(#msg"\n") 이라는 매크로가 있을 때 이 매크로의 치환 결과는 다음과 같다.

 

호출부

치환 결과

출력 결과

println(메시지);

printf("메시지\n")

메시지

println("메시지");

printf("\"메시지\"\n")

"메시지"

println("""");

printf("\"\"\"\"\n")

""""

 

#연산자를 잘 활용하면 2진수 형태의 상수를 표기할 수 있다. C++은 8진, 10진, 16진 상수 표기법은 지원하지만 2진 상수 표기법은 지원하지 않으므로 암산을 통해 16진수로 만들어야 한다. 꼭 필요할 경우 좀 색다른 방법을 동원할 수 있는데 표준 함수중에 문자열을 수치로 변환하는 strtol 함수는 기수를 지정할 수 있다. 그래서 2진수 형태의 문자열로부터 원하는 값을 만들어 내는 것이 가능하다. 예를 들어 이진수 00110100 상수를 정의하고 싶다면 strtol("00110100",NULL,2)라고 호출하면 된다.

그런데 이 함수를 매번 호출하는 것은 무척 번거로우므로 좀 더 편리하게 사용할 수 있는 매크로 함수를 정의하고 싶다고 하자. 문제는 이 함수가 요구하는 2진 표기가 반드시 문자열이어야 한다는 점이다. 이럴 때 #연산자를 사용하면 실인수를 문자열로 바꿔 주므로 2진값을 바로 적어도 된다. 다음은 2진 상수를 표기하는 BIN 매크로이다.

 

  : BinaryConst

#include <Turboc.h>

 

#define BIN(a) strtol(#a,NULL,2)

 

void main()

{

     printf("%x\n",BIN(00010010001101001111000001011100));

}

 

BIN 매크로의 실인수로 2진수 표기를 적기만 하면 이 표기를 문자열로 바꾼 후 strtol 함수에 의해 수치값으로 변환되어 리턴될 것이다. 출력 결과는 16진수 1234f05c이며 BIN 매크로의 2진수와 같은 값이다. 이 매크로는 문자열을 거쳐 수치를 만들어 내므로 효율은 좋지 못하지만 2진수 암산이 잘 안되는 사람에게는 아주 유용하다.

## 연산자(merge operator) 역시 #define 문 내에서만 사용되며 형식 인수 사이에 위치한다. 형식 인수를 분리하여 각각 치환되도록 하며 치환 후에는 주변의 공백과 함께 사라져 두 인수의 치환 결과가 하나의 토큰으로 연결될 수 있도록 한다. 다음 예제를 보자.

 

  : SharpSharpOp

#include <Turboc.h>

 

#define var(a,b) (a##b)

 

void main()

{

     int var(Total, Score);

     TotalScore=256;

     printf("총점 = %d\n",TotalScore);

}

 

var 매크로는 두 개의 형식 인수를 받아 들여 이 두 명칭을 연결해서 하나의 명칭으로 만드는데 형식 인수 a와 b 사이에 ## 연산자가 사용되었다. 만약 ## 연산자없이 var(a,b) (ab)로 정의한다면 전처리기가 ab를 a와 b 인수가 아닌 별도의 명칭으로 인식하므로 실인수로 치환되지 못하고 그대로 ab로 남아 있을 것이다. 이 두 형식 인수가 ##에 의해 구분됨으로써 양쪽 모두 실인수로 치환되며 치환 후에 ##은 사라진다. var(Total, Score)가 치환되는 과정은 다음과 같다.

 

var(Total, Score)

 

Total##Score 인수 치환

 

TotalScore    치환 후 ##은 사라진다

 

##은 주변의 공백까지 같이 제거하므로 매크로 정의문의 ## 좌우 공백은 무시된다. (a##b)로 쓰나 (a ## b)로 쓰나 결과는 동일하다. ##은 치환전에 두 토큰을 분리하여 각 토큰이 치환될 수 있도록 구분하는 역할을 하며 치환 후에는 주변의 공백과 함께 자폭하여 두 토큰을 하나로 연결한다. 이 연산자는 주로 일괄적인 타입 정의에 사용된다.

 

  : DefineType

#include <Turboc.h>

 

#define defptype(type) typedef type *p##type

 

void main()

{

     defptype(int);

     defptype(double);

     defptype(char);

 

     pint pi;

     int i=3;

     pi=&i;

     printf("i = %d\n",*pi);

}

 

defptype 매크로는 int, double 등의 타입을 인수로 전달받으며 원래 타입앞에 p를 붙여 포인터 타입을 새로 정의한다. 예를 들어 defptype(int)는 정수형 포인터 pint를 정의하고 defptype(double)은 실수형 포인터 pdouble을 정의한다. 형식 인수 type이 매크로 호출문으로 전달된 실인수(int, double 등)으로 먼저 치환된 후 앞에 p자를 붙이기 위해 ##이 치환을 돕고 있다. 사용자 정의 타입에 대해서도 물론 사용할 수 있다.

이런 목적으로 사용되는 ##연산자는 윈도우즈의 표준 헤더 파일과 메시지 크래커, MFC 소스 코드, COM 헤더 파일에서 흔히 발견할 수 있다. 다음이 몇 가지 예이다.

 

#define OLESTR(str)     L##str

#define MAKE_ENUM(Method, Interface)    Interface##_##Method

#define HANDLE_MSG(hwnd, message, fn)    \

    case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))

#define RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))

static const AFX_DATA CRuntimeClass class##class_name; \

 

매크로 정의문들이 하나같이 무척 복잡해 보이는데 이런 매크로의 도움으로 실제 코드는 훨씬 더 간단해질 수 있는 것이다. 이 코드들은 관련 부분에서 다시 살펴볼 기회가 있을 것이며 또한 분석해봐야 한다. 당장 이 문장들의 의미를 분석할 수는 없겠지만 장래 이 매크로를 분석해야 할 때를 대비해서 여기서는 ## 연산자의 정의와 동작에 대해서만 잘 정리해 두도록 하자.

행 계속 문자로 알려진 \도 일종의 전처리 연산자이며 자신과 뒤쪽의 개행 문자를 없는 것으로 취급하여 두 줄을 하나로 연결하는 용도로 사용한다. 이 문자가 행 끝에 올 때 자신의 뒤쪽에 있는 공백들과 개행코드까지 몽땅 제거하는 역할을 한다. 그래서 다음 문장은 두 행으로 분리되어 있지만 전처리 후에 한 문장으로 합쳐진다. 초기화할 문자열이 한 행에 다 쓸 수 없을만큼 길어질 때 줄 끝에 \를 적고 개행한 후 계속 쓰면 된다.

 

char Message[]="이 문자열은 \

아래의 문자열과 합쳐집니다.";

 

단, \ 연산자는 기계적으로 두 행을 연결할 뿐이며 다음 행의 선두에 있는 공백까지도 윗줄에 붙이기 때문에 두 번째 줄을 들여쓰기해서는 안되는 불편함이 있다. 그래서 이 방법보다는 문자열 상수를 연속으로 적는 방법이 더 편리하다. 재미있는 것은 이 연산자가 컴파일되기 전에 처리되기 때문에 명칭의 중간에도 사용할 수 있다는 점이다. printf를 pri\까지만 쓰고 다음행에 나머지 ntf를 적어도 잘 동작한다. 물론 이렇게 해야 할 이유는 없지만 전처리 과정이 컴파일 전에 수행된다는 것을 보여주는 명백한 증거로 볼 수 있다. 어쨌든 약간 재미있기는 하다.


출처 : http://www.winapi.co.kr/clec/cpp2/18-2-1.htm

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

문자열 _T("")와 L""  (0) 2015.02.07
레지스트리의 값 가져오기  (0) 2015.02.07
strncpy 와 strncpy_s 에 대한 오해  (0) 2015.02.07
함수 포인터 typedef  (0) 2015.02.07
enum, 보다 나은 enum  (0) 2015.02.07
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

strncpy()는 복사되었으면 하는 문자열의 길이를 넘어서지 않게 복사해 준다. 
그리고 대상 버퍼를 넘어서게 되면 NULL로 끝나지 않는 문자열까지 복사하게 된다. 예를 들면 아래와 같다. 

strncpy(dest, 8, "1234567"); // dest == { '1', '2', '3', '4', '5', '6', '7', NULL } 
strncpy(dest, 8, "12345678"); // dest == { '1', '2', '3', '4', '5', '6', '7', '8' } 


strncpy_s() 는 대상 버퍼가 실제 수용가능한 크기와 복사되었으면 하는 문자열의 길이 두가지를 넘긴다. 
strncpy()와 strncpy_s()의 다른점이 있다면 strncpy_s()는 '복사 되었으면 하는 문자열의 길이'를 넘어서서 복사를 할 때 마지막을 항상 NULL로 끝나게 해준다는 점이다. 

다음과 같은 코드는 런타임 에러를 발생시킨다. 

// 이 코드는 buf에 1, 2, 3, 4, 5, 6, 7, 8, NULL .. 총 9개의 문자열을 넣으려다가 에러가 나게 된다. 
char dest[8]; 
strncpy_s(buf, _countof(buf), "123456789000", _countof(buf)); 


따라서 strncpy_s()를 사용할 때는 버퍼 크기와, 복사하고 싶은 길이를 다르게 주어야 한다. 

char dest[8]; 
strncpy_s(buf, _countof(buf), "123456789000", _countof(buf)-1); 


참고. 

strcpy_s()를 사용하면 버퍼 크기를 넘어서는 데이터를 넘을 때 
자동으로 막아준다고 착각하는 경우가 있다. (strncpy처럼) 

strcpy_s()에 넘기는 2번째 인자인 dest_size는 '내가 이 정도까지만 복사하고싶다'의 의미가 아니라 
'여기 지정한 크기를 넘어서 복사하려고 하면 프로그램을 멈추고 에러창을 띄워라' 의 의미로 보아야 한다. 

// 이 코드는 이쁘게 dest에 1234567까지만 복사해 주는 것이 아닌, 프로그램을 뻗게 하는 코드다. 
char dest[8]; 
strcpy_s(dest, _countof(dest), "123456789"); 


연장해서 sprintf_s() 와 _snprintf_s() 에도 똑같이 적용된다. 

sprintf_s(buf, _countof(buf), "%s 1234567", "1212"); // 프로그램 오류를 내는 코드 
_snprintf_s(buf, _countof(buf), _countof(buf), "123456789%d", 121212); // strncpy_s()와 같은 이유로 오류를 내는 코드 
_snprintf_s(buf, _countof(buf), _countof(buf)-1, "1234567%d", 121212); // 정상적으로 작동하며, 이렇게 써야 하는 코드


출처 : http://gpgstudy.com/forum/viewtopic.php?p=97501

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

레지스트리의 값 가져오기  (0) 2015.02.07
# 과 ##  (0) 2015.02.07
함수 포인터 typedef  (0) 2015.02.07
enum, 보다 나은 enum  (0) 2015.02.07
vector 와 map 의 erase 를 할때 주의점  (0) 2015.02.07
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

함수 포인터의 타입은 함수가 취하는 인수들의 타입과 리턴값까지 정확하게 밝혀야 하기 때문에 타입의 형식이 너무 길어서 쓰기에 번거롭다. 또한 함수 포인터로부터 파생된 타입을 만드는 것도 헷갈리고 생소한 면이 있다. 그래서 함수 포인터 타입을 자주 사용하거나 자신이 없다면 직접 타입을 기술하는 것보다 typedef로 함수 포인터 타입을 따로 정의한 후 사용하는 것이 편리하다. int func(int)형의 함수를 가리키는 타입은 다음과 같이 정의한다.

 

typedef int (*PFTYPE)(int);

PFTYPE pf;

 

함수 포인터를 선언하는 문장에서 변수명을 원하는 타입 이름으로 바꾸고 앞에 typedef만 붙이면 된다. 이후 컴파일러는 PFTYPE이라는 명칭을 int (*)(int) 타입으로 인식하므로 PFTYPE으로 함수 포인터 변수를 쉽게 선언할 수 있으며 캐스트 연산자로도 사용할 수 있다. 또한 함수 포인터로부터 배열이나 포인터같은 파생 변수를 선언하는 것도 훨씬 더 간편하다.


출처 : http://winapi.co.kr/clec/cpp2/15-2-2.htm

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

# 과 ##  (0) 2015.02.07
strncpy 와 strncpy_s 에 대한 오해  (0) 2015.02.07
enum, 보다 나은 enum  (0) 2015.02.07
vector 와 map 의 erase 를 할때 주의점  (0) 2015.02.07
64비트 int (INT64) printf 에서 출력하기  (0) 2015.02.07
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

#define 과 얼핏 비슷해 보이지만비슷한 유형별의 데이터를 표현하기 위해 반드시 필요한 C++의 필수 타입인 enum 의 몇 가지 재미있고 유용한 팁을 소개합니다.

 

1. namespace 와 결합하기

 

일반적으로 enum 을 이용하여 타입이름을 짓기란 쉬운 일이 아닙니다.

만약 리스트에 필요한 정렬 기준을 enum 으로 표현한다면 아래 정도가 됩니다.

 

enum SORT_LIST

{

           SORT_DATE,                 // 날짜순

           SORT_NAME,                // 이름

           SORT_CONTENT, // 내용

           S0RT_ETC,                    // 기타

};        

 

bool SortSomeData(SORT_LIST SortList)

{

           switch (SortList)

           {

           case SORT_DATE:

                     break;

           case S0RT_NAME:

                     break;

           // ....

           }

}

 

 

하지만이러한 enum 표현 방식은

  •  SORT_DATE 라는 이름은 너무 흔합니다.  프로그램이 조금만 커져도 이러한 이름들이 다른 곳에서도 필요하게 되어 이름 충돌을 피하기 힘들어 집니다.  이름 충돌을 피하기 위해서는SORT_LIST를 변경해도 아무런 소용이 없고 SORT_DATE 를 완전히 다른 이름으로 지어야만 합니다.
  • enum 의 타입이름인 SORT_LIST와 실제 값인 SORT_DATE 를 서로 연관 짓기가 힘듭니다. switch 문 내에서도 타입이름(SORT_LIST)은 사용되지 않아서 SORT_DATE만 보고 이 값이SORT_LIST 의 한 유형인지 구분 짓기 힘듭니다
  • enum 값에 항상 들어 있는 SORT 라는 prefix 도 부담스럽습니다. SORT_XXX 식으로 이름을 짓다 보니타입핑하기도 힘들구요

 

평소 이런 문제에 대해서 알고는 있었지만 그 해결책을 고민만 하던 차에 아주 좋은 해결책을 발견했습니다바로 아래 글에서요. (늘 해결책은 제가 아닌 책이나 다른 글에서 구합니다.)

 

Stupid C++ Tricks #2: Better Enums

 

이 글에서 제안하는 방식은 enum  namespace과 결합하여 가독성을 증가 시키고이름충돌도 최소화시키는 방식입니다. 위에 든 예를 namespace 식으로 표현하면 다음과 같습니다.

 

namespace SortList

{

           enum Enum

           {

                     BytDate, // 다가올날기준

                     ByName,                     // 이름

                     ByContent,        // 내용

                     Etc,

           };        

}

 

bool SortSomeData(SortList::Enum SortList)

{

           switch (SortList)

           {

           case SortList::ByDate:

                     break;

           case SortList::ByName:

                     break;

           // ....

           }

}

 

namespace 와 결합함으로써, enum 의 각 항목에는 항상 SortList 라는 namespace가 따라 붙게 되어 가독성이 증가함을 알 수 있습니다SORT_DATE  보다는 SortList::ByDate 가 읽기 쉽고요즘 웬만한IDE 에서는 namespace SortList::만 입력하면 자동으로 이하 소속되는 타입이름들이 나열되기 때문에 미스타이핑 할 가능성도 줄여주네요.


사용자 삽입 이미지



게다가 namespace 를 사용하기 때문에 다른 모듈과 이름이 충돌할 가능성도 줄어들었습니다.

이름 충돌이 없기 때문에 아래와 같이 NameEdit 라는 enum 값을 여러 namespace 에 걸쳐 사용하면서 각각의 의미에 맞는 값들을 줄 수가 있게 됩니다.

 

namespace ControlWidth

{

           enum Enum

           {

                     NameEdit = 20,

                     AddressCombo = 60,

                     OkBtn = 30;

                     // ....

           };

};

 

namespace ControlID

{

           enum Enum

           {

                     NameEdit = 100,

                     AddressCombo = 101,

                     OkBtn = 102;

                     // ....

           };

}

 

이와 같이 enum 을 표시하는 방식은 실제 꽤 유용하게 써 먹을 수 있어서 지금 새로 만들고 있는 프로젝트에서도 재작성하는 코드에서 enum 타입을 위 방식으로 변경하고 있는 중입니다.

괜찮은 방법 아닌가요 ? ^^;

 

 

2.  enum 에 문자열 결합하기


2번째 팁은 숫자로만 되어 있는 enum 을 문자열로 치환하는 팁입니다.

C++ 에서 enum 을 정수형으로만 치환가능하기 때문에 사용자가 읽을 수 있는 텍스트로 변경하기 위해서는 enum 값에 1:1 매칭되는 텍스트가 필요한 경우가 많습니다.

이를 해결하는 방법으로 아래 포스팅에서는 enum  #define 매크로를 이용해서 문자열을 매칭시키는 방법을 소개합니다.

 

Enums, Macros, Unicode and Token-Pasting

 

Visual C++ Team Blog 에 소개된 이 방법은 숫자로이뤄진 enum 값과

 

enum Animal { dog, cat, fish, bird };

 

문자로이뤄진char값을매칭시키는방안에대한내용입니다.

 

wchar_t* AnimalDiscription[] = { L"dog", L"cat", L"fish", L"bird" };

 

이를 위해 animal.inc 파일에 아래 라인들을 추가하고

 

MYENUM(dog)

MYENUM(cat)

MYENUM(fish)

MYENUM(bird)

 

아래와 같이 enum 을 선언합니다.

 

enum Animal {

#define MYENUM(e) _##e,

#include "animal.inc"

#undef MYENUM

};

 

wchar_t* AnimalDescription[] = {

#define MYENUM(e) L"_" L#e,

#include "animal.inc"

#undef MYENUM

};

 

#define 으로 조금 복잡해 보여서 그렇지, enum 값과 wchar_t* 배열의 선언을 MYENUM 매크로 정의를 통해 확장하는 식입니다.  조금 특이한 것은 MYENUM  enum  wchar_t* 배열 속에서 조금씩 다르게 선언하고데이터를 추가한 후( #include "animal.inc") 에는 바로 undefined 시켜버리는 정도네요

 

이 방법 마음에 드시나요?

해당 링크에 달린 댓글들을 보면 많은 분들이 마음에 들지 않나 봅니다.

가장 크게 문제 삼은 내용은 역시 아래 글과 같은 #define 매크로에 대한 조금 헤묵은 논쟁들입니다.

 

Macros is something C++ (especially the Standards Committee) has always tried to avoid. Such use of macros like this will make code unreadable and cause maintainance problems. I think it's not a good idea to play with such thing.

 

개인적으로는 #define 을 활용한 매크로 활용을 좋게 보고 있습니다.

제가 #define을 좋아하는 이유는

  • 코딩량을 줄여 줍니다코딩하는 량이 줄어든다는 것은 그만큼 유지관리할 코드가 줄어 들고,미스타이핑에 의한 작은 실수들을 걸러주기 때문입니다.
  • 자주 해야 하지만 귀찮은 작업들 - Get/Set 함수 같은 - 을 쉽게 처리해 줍니다저 같은 경우 클래스 하나를 만들면 대부분은 private 멤버변수들이어서 늘 public 으로 Get/Set 함수를 구현하는 게 고역 중에 고역인데요.  #define 매크로를 활용하면 늘 심플하고 코드 보기도 편하더군요.


Visual C++ 에 있는 _countof 매크로도 정말 없어서는 안될 매크로 중 하나입니다.

 

extern "C++"

{

template <typename _CountofType, size_t _SizeOfArray>

char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];

#define _countof(_Array) sizeof(*__countof_helper(_Array))

}

 

아무튼논란의 여지가 있긴 하지만이 팁의 주요 목적은 enum Type 으로 추가할 숫자값과문자열 값이 어느 하나만 추가되거나삭제되지 않고 늘 한번에 관리 될 수 있도록 하기 위한 방안 중에 하나라고 봅니다.  유용했다면 쓰면 될 것이고 그렇지 않으면 안 쓰면 되겠죠 :-)

댓글 중에는 하나의 .inc  include 할 필요 없이 하나의 파일에서 모두 해결하는 방안도 있으니 참고하세요

 

#define ANIMALS(FOO) \

FOO(dog) \

FOO(fish) \

FOO(cat)

 

#define DO_DESCRIPTION(e)  L"_" L#e,

#define DO_ENUM(e)  _##e,

 

wchar_t* AnimalDescription[] = {

ANIMALS(DO_DESCRIPTION)

};

 

enum Animal {

ANIMALS(DO_ENUM)

};

 

 

3.  enum 의 처음과 끝을 지정하자

 

1, 2번에 비하면 좀 약한 팁입니다만, enum 을 사용할 때 처음과 끝을 지정하자는 아이디어는 Code Complete 2 책에 p436 에 나와있습니다.

아래와 같은 국가명을 열거할 필요가 있을 때처음과 끝에 해당하는 값을 XXX_FIRST 와 XXX_LAST로 지정하는 방법입니다.

 

enum Country

{

           Country_First = 0,

           Country_China = 0,

           Country_England = 1,

           Country_France = 2,

           Country_Germany = 3,

           Country_India = 4,

           Country_Korea = 5,

           Country_Japan = 6,

           Country_Usa = 7,

           Country_Last = 7,

};

 

XXX_FIRST 와 XXX_LAST 가 시작과 끝을 가르키기 때문에 이를 활용하여 열거형의 모든 항목을 조회하여 원하는 일을 할 때 유용합니다.

 

for (Country cty = Country_First; cty <= Country_Last; cty++)

{

           // 원하는로직수행

}

 

추후 새로운 국가 Country_Italy 를 추가한다면 아래와 같이 enum 만 수정하면 enum 을 사용하는 for loop 는 손대지 않아도 되는 장점이 생깁니다.

 

           Country_Usa = 7,

           Country_Italy = 8,

           Country_Last = 8,

}

 

이상 enum 을 활용하는 몇 가지 팁을 알아 봤습니다 혹시 나만의 좋은 팁이 있으시면 같이 공유해 주세요.


출처 : http://eslife.tistory.com/300


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

strncpy 와 strncpy_s 에 대한 오해  (0) 2015.02.07
함수 포인터 typedef  (0) 2015.02.07
vector 와 map 의 erase 를 할때 주의점  (0) 2015.02.07
64비트 int (INT64) printf 에서 출력하기  (0) 2015.02.07
try catch 문 대체  (0) 2015.02.07
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

vector 는 erase 를 한 후에 다음 위치를 반환하지만 map 은 반환이 없으므로 이런식으로 짜야한다


v 는 vector

m 은 map

 

for( it = v.begin(); it != v.end(); )

{

    if( (*it) % 2 )

        it = v.erase( it );

    else

        ++it;

}

 

for( it = m.begin(); it != m.end(); )

{

    if ( it->second % 2 )

    {

        m.erase( it++ );

    }

    else

    {

        ++it;

    }

}


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

함수 포인터 typedef  (0) 2015.02.07
enum, 보다 나은 enum  (0) 2015.02.07
64비트 int (INT64) printf 에서 출력하기  (0) 2015.02.07
try catch 문 대체  (0) 2015.02.07
공간 속의 두 점 사이의 거리  (0) 2015.02.07
Posted by 역시인생한방
,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

printf 뿐만 아니라 sprintf 나 CString 의 Format 에서도 사용 가능합니다.
64비트 숫자를 %d 로만 출력했을시 int 32bit 의 수가 넘어가면 이상하게 출력되는 것을 막아주는 코드입니다.


INT64 i64;
printf( "%I64d", i64 );

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

enum, 보다 나은 enum  (0) 2015.02.07
vector 와 map 의 erase 를 할때 주의점  (0) 2015.02.07
try catch 문 대체  (0) 2015.02.07
공간 속의 두 점 사이의 거리  (0) 2015.02.07
stringstream  (0) 2015.02.07
Posted by 역시인생한방
,