변수 명명법
윈도우즈 프로그래밍에서 주로 사용되는 접두어들이 존재한다.
접두어 | 원래말 | 의미 |
cb | Count of Bytes | 바이트 수 |
dw | double word | 부호없는 long형 정수 |
h | handle | 윈도우, 비트맵, 파일 등의 핸들 |
sz | Null Terminated | NULL 종료 문자열 |
ch | Character | 문자형 |
a | Array | 배열 |
w | Word | 부호없는 정수형 |
i | Integer | 정수형 |
p, ip | long pointer | 포인터형 |
b | Bool | 논리형 |
윈도우즈 프로그래밍에서 쓰이는 이런 변수 명명법을 헝가리식 명명법이라고 한다.
물론 이렇게 쓰면 편하다 라는 관례이지, 필수조건은 아니다.
유니코드
유니코드는 16비트의 단일한 값으로 지구상의 모든 문자를 표현할 수 있는 문자 코드 체계이다.
유니코드를 지원하려면 문자형이나 문자열에 대해 C언어의 타입을 바로 쓰지 말고 유니코드 설정에 따라 변경되는 중간 타입을 사용해야 한다.
C언어에 익숙한 사람들은 앞으로 문자나 문자열을 표현할 때 다음 타음을 사용해야 한다.
C 타입 | 유니코드 타입 |
char | TCHAR |
char * | LPSTR |
const char * | LPCTSTR |
문자열을 다루는 함수들도 C의 표준 함수를 쓰지 말고, 가급적 유니코드를 인식하는 함수를 사용한다.
보통 비슷하며, l 자가 앞에 붙는 것이 특징이다.
C 표준 함수 | 유니코드 지원 함수 |
strlen | lstrlen |
strcpy | lstrcpy |
strcat | lstrcat |
strcmp | lstrcmp |
sprintf | wsprintf |
예로, strlen은 char 타입의 문자열 길이만 조사하지만, lstrlen은 char와 TCHAR 타입의 문자열에 대해서도 동작한다.
또한 문자열 상수 타입이 존재하므로 쌍따옴표 안에 바로 문자열 상수를 넣지말고 TEXT 매크로로 둘러 싸는 것이 좋다.
TCHAR* str = "string";
TCHAR* str = TEXT("string");
마찬가지로 TEXT 매크로 또한 유니코드로 컴파일할 때는 각 문자가 16비트의 유니코드 문자가 된다.
그렇지 않을 경우, 8비트의 안시(ANSI) 문자가 된다.
64비트 API
이전의 경우, 16비트 환경에서 32비트로의 이전은 많은 변화들이 있었다.
다행히 32비트에서 64비트로의 이전은 큰 변화가 없다.
Win32의 모든 함수들은 거의 변화없이 64비트에서도 지원되며 32비트 응용프로그램들도 약간의 노력으로 64비트로 포팅할 수 있다.
그러니, 제일 중요한 것은 하나의 소스코드로 32비트, 64비트 실행 파일을 동시에 컴파일 할 수 있도록 이식성을 확보하는 것이다.
64비트도 종류에 따라 각각 컴파일 해야하므로,
- 32비트 실행파일
- (인텔) IA64용 실행파일
- (AMD) X64용 실행파일
으로 최소 3개의 실행 파일을 만들어내야 한다.
추가로 64비트에서 가장 달라지는 점은 주소 공간이 확대됨으로 포인터의 크기가 64비트로 확장된 것이다.
포인터 타입외에 int나 long는 여전히 32비트를 유지하는데, 64비트가 된다면 낭비가 심해지기 때문이다.
만약 실행되는 환경에 상관없이 일정한 길이를 가져야 한다면, 아래의 타입을 사용해야 한다.
길이 | 부호있음 | 부호없음 |
32비트 | INT32, LONG32 | UINT32, ULONG32, DWORD32 |
64비트 | INT64, LONG64 | UINT64, ULONG64, DWORD64 |
혹여, 컴파일되는 환경에 따라 길이가 달라져야 한다면 아래의 타입을 사용해야한다.
INT_PTR, LONG_PTR, UINT_PTR, ULONG_PTR, DWORD_PTR
뒤에 _PTR이 붙은 타입은 운영체제의 비트수에 따라 크기가 가변적이며, 포인터와 같은 길이를 가진다.
포인터와 호환되어야 하는 정수가 필요할 때는 위와 같은 타입을 사용한다.
아래는 예시이니 참고하자.
void DisplayInfo(int Type, int Value)
{
TCHAR Info[128];
switch(Type){
case 1:
wsprintf(Info,"나이는 %d입니다.",Value);
break;
case 2:
wsprintf(Info,"이름은 %s입니다.",(TCHAR*)Value);
break;
}
MessageBox(hWnd,Info,"정보",MB_OK);
}
DisplayInfo(1,25)
DisplayInfo(2,(int)"김민규");
여기서 "김민규" 는 문자열 리터럴로 (int)"김민규" 는 메모리에 저장된 주소를 의미한다.
(int) 로 메모리 주소를 int 형으로 받고, 이 이후 (TCHAR *) 로 다시 캐스팅 되어 반환받는다.
이를 간단하게 확인하는 코드는 아래와 같다.
#include <stdio.h>
int main() {
const char* str = "Hello";
int address = (int)str; // 주소를 정수로 변환
printf("Original Pointer: %p\n", str); // 문자열 리터럴의 주소 출력
printf("Integer Address: %d\n", address); // 정수로 변환된 주소 출력
// 정수를 다시 포인터로 변환
const char* restored = (const char*)address;
printf("Restored Pointer: %s\n", restored); // 문자열 출력
return 0;
}
결과
Original Pointer: 0x7ffeefbff6a0
Integer Address: 140732814843680
Restored Pointer: Hello
'개발 > Win API' 카테고리의 다른 글
3. 출력 (1) | 2025.01.02 |
---|---|
2. Win API 첫번째 예제 (2) | 2024.11.26 |