I'm FanJae.

[System Programming] 프로그램 구현 관점에서 64비트 기반 프로그래밍 / 오류의 확인 본문

System Programming

[System Programming] 프로그램 구현 관점에서 64비트 기반 프로그래밍 / 오류의 확인

FanJae 2024. 9. 11. 23:08

1. 64비트 기반 프로그래밍

- 64비트 시스템을 고려한 프로그래밍으로 자료형에 대해서 고려해야 한다.

 

1-1. LLP64 vs LP64

운영체제 모델 char short int long 포인터
Windows LLP64 1바이트 2바이트 4바이트 4바이트 8바이트
Linux LP64 1바이트 2바이트 4바이트 8바이트 8바이트

- 핵심은 64비트에서는 포인터가 8바이트로 표현된다.

- 또한, Linux의 경우 long은 8바이트로 표현된다는 차이가 있다.

 

1-2. 64비트와 32비트 공존의 문제점

- 데이터 손실의 문제

#include <stdio.h>
int main(void)
{
    int arr[10] = {0, };
    int arrVal = (int) arr; // 데이터 손실이 발생할 수 있다.
    printf("pointer : %d \n", arrVal);
    return 0;
}

 

1-3. Windows 스타일 자료형

- 이 부분은 표를 직접적으로 첨부하는 것 보다는 공식 문서를 첨부하려고 한다.

- 링크 : https://learn.microsoft.com/en-us/openspecs/windows_protocols/MS-WINPROTLP/1593dc07-6116-4e9e-8aeb-85c7438fab0a

 

1-4. Polymorphic 자료형

- 다양한 모습이 있다라는 의미이다. 객체 지향 프로그래밍에서 이 개념을 다형성이라는 개념이 존재한다.

- 자료형이 다형적이라는 것은 상황이나 환경에 따라서 그 자료형이 의미하는 바가 유동적이라는 뜻이다.

#if defined (_WIN64)
	typedef __int64 LONG_PTR;
	typedef unsigned __int64 ULONG_PTR;
	typedef __int64 INT_PTR;
	typedef unsigned __int64 UINT_PTR;
#else
	typedef long LONG_PTR;
	typedef unsigned long ULONG_PTR;
	typedef int INT_PTR;
	typedef unsigned int UINT_PTR;
#endif

- PTR이라고 적혀있지만 포인터가 아니다.

- 포인터 값 기반의 산술 연산을 위해 정의된 자료형이다.

 

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>

// 메모리 공간 거리 차이를 계산하는 64비트용 함수
UINT64 CalcDistance(UINT64 a, UINT64 b)
{
	return b - a;
}

// 메모리 공간 거리 차이를 계산하는 32비트용 함수
UINT CalcDistance(UINT a, UINT b)
{
	return a - b;
}

int _tmain()
{
	INT val1 = 10;
	INT val2 = 20;

	// 32비트 환경
	_tprintf(_T("Position %u, %u \n"), (UINT)&val1, (UINT)&val2);
	_tprintf(_T("Distance: %u \n"), CalcDistance((UINT)&val1, (UINT)&val2));

	// 64비트 환경
	_tprintf(_T("Position %llu, %llu \n"), (UINT64)&val1, (UINT64)&val2);
	_tprintf(_T("Distance: %llu \n"), CalcDistance((UINT64)&val1, (UINT64)&val2));

	return 0;
}

- 메모리 공간상 거리를 계산해 주는 함수를 구현할 때, 32비트와 64비트간 차이가 존재한다.

- 이에 따라서 서로 다른 함수를 별도로 구현해야 한다.

- C++에서는 함수 오버로딩이 가능하여 위와 같이 구성 가능하겠지만 별로 좋지 못하다.

- 또한, 조건부 컴파일 역시 별로 좋은 방법이 아니기 때문에 Polymorphic 자료형을 사용해서 처리가 가능하다.

 

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>

// 메모리 공간상 거리 차이를 계산하기 위한 함수 (x64, 64비트)
UINT_PTR CalcDistance(UINT_PTR a, UINT_PTR b)
{
	// 32비트라면
	//return a-b;
	return b - a;
}

int _tmain()
{
	INT val1 = 10;
	INT val2 = 20;
	
	_tprintf(_T("Distance: %u \n"), 
        CalcDistance((UINT_PTR)&val1, (UINT_PTR)&val2));

	return 0;
}

- UNIT_PTR은 Polymorphic 자료형이므로, 실행 환경에 따라 결정된다.

- 즉, 32비트 시스템에서는 32비트로, 64비트 시스템에서는 64비트로 선언된다.

 

2. 오류의 확인

- 프로그램을 개발하는 과정에서 오류가 자주 발생한다. 이는 당연하다.

- 오류가 생기는건 어쩔 수 없는 일이지만 오류가 생긴 원인을 파악하고 해결이 중요하다.

 

2-1. GetLastError 함수와 에러코드

- Windows 시스템 함수를 호출하는 과정에서 오류가 발생시 GetLastError 함수 호출로 오류의 원인을 확인할 수 있다.

- Windows 시스템 함수들은 오류 발생시 NULL을 반환하여 오류의 원인을 알 수 없다.

- GetLastError 함수 호출시 오류의 원인에 해당하는 에러코드를 얻어올 수 있다.

- 이것에 대한 정보는 MSDN을 통해 확인이 가능하다.

- 관련 링크 : https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes

 

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>

int _tmain()
{
	HANDLE hFile = CreateFile(_T("ABC.DAT"), GENERIC_READ, FILE_SHARE_READ, NULL,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    
	if (hFile == INVALID_HANDLE_VALUE)
	{
		_tprintf(_T("Error code: %d\n"), GetLastError());
		return 0;
	}
	return 0;
}

- MSDN에서는 다음과 같이 시스템 코드를 정의하고 있다.

- 즉, FILE_NOT_FOUND로 파일을 찾지 못했다는 뜻이다.

 

이처럼, 오류 발생시 GetLastError 함수 호출을 통해 오류 코드를 확보가 가능하다.

Comments