WIN32 vs WIN64

수민·2023년 8월 23일
0

CS 공부

목록 보기
2/5
post-thumbnail

인프런 강의 : 뇌를 자극하는 윈도우즈 시스템 프로그래밍을 듣고 정리한 학습 목적의 글입니다.
문제 시 댓글 혹은 메일 주시면 감사하겠습니다.


WIN32 vs WIN64

32비트 / 64비트 구분 방법

  1. 한 번에 송수신 가능한 데이터의 크기
    : I/O Bus에 의존적
    I/O Bus 시스템이 32비트냐, 64비트냐에 따라 결정된다.

  2. 데이터 처리 능력
    : CPU가 한 번에 읽어 들일 수 있는 (fetch할 수 있는) 명령어의 크기

만약,
데이터를 이동시킬 때는 64비트로 이동시켰는데, CPU가 내부적으로 32비트로 처리한다?
ㄴ 완벽한 64비트라고 할 수 없음.
반대의 경우도 마찬가지..

데이터를 처리하는 애 / 데이터를 송수신하는 애
두 개가 동일한 사이즈로 주고 받아야 한다.
(아니라면 어디선가 병목일어날 수 있음)

따라서 둘 다 64비트로 처리해야 64비트 시스템이라고 할 수 있겠다.

32비트에서 64비트로의 진화

32비트 시스템에서 프로그래밍하다가, 64비트 시스템으로 바뀌면 뭐가 좋아졌냐면,

  1. 프로그램으로 표현할 수 있는 범위의 증가

  2. 표현할 수 있는 메모리의 전체 크기

포인터의 크기 ?

32비트 시스템에서는 포인터가 32비트 (4바이트)
64비트 시스템에서는 포인터도 64비트 (8바이트)

포인터가 클 수록 접근 가능한 주소의 값이 크다.
== 메모리에 접근할 수 있는 범위가 크다.

만약 주소가 128비트라면, 64비트 데이터를 한 번에 전송할 수 있으므로 두 번에 전송해야 한다.
== 하나의 주소를 표현하기 위해 I/O Bus를 두 번 사용해야 한다.
-> 상당한 성능 저하 !!

그래서 메모리는 크면 클 수록 좋다.
BUS에서 한 번에 전송할 수 있는 데이터의 크기만큼 키워주는게 좋다.
-> n비트 시스템에서는 한 번에 데이터를 n비트씩 송수신할 수 있도록 주소를 n비트로 표현하는 것이 성능에 좋다 !!

전체를 접근할 수 있도록 포인터의 크기 (주소값의 크기)가 충분히 커야 한다 !

32비트 시스템 : 한 번에 접근할 수 있는 메모리 = 0 ~ 2^32 - 1 = 4GB
64비트 시스템 : 한 번에 접근할 수 있는 메모리 = 0 ~ 2^64 - 1

즉,
32비트 시스템에서 64비트 시스템으로의 전환은,
프로그램 상에서 활용할 수 있는 최대 메모리의 크기가 증가했다는 것을 의미한다.

예제 : 활용 가능한 메모리의 확장

활용 가능한 메모리가 50Byte라고 가정하자.
50바이트짜리 시스템에서 아래와 같이 프로그래밍하면, 안돌아간다.
TCHAR가 1바이트라고 하더라도 100바이트.
이렇게 메모리를 할당할 수 없다.

1번

int _tmain(void)
{
	TCHAR str[100];
    _tscanf(_T("%s"), str);
    _tprintf(_T("%s"), str);
    return 0;
}

그래서 아래와 같이 고쳐서 프로그래밍해야 한다.
아래 처럼 프로그래밍하면 같은 기능을 메모리를 최소한으로 사용하면서 구현할 수 있다.

2번

int _tmain(void)
{
	TCHAR ch;
    do {
    	_tscanf(_T("%c"), &ch);
    	_tprintf(_T("%c"), ch);
    } while(ch != '\n');
    return 0;
}

다만,
1번은 저장된 문자열을 한 번에 읽어들일 수 있다.
2번은 한 문자씩 계속 읽어들여야 한다.

이론식으로만 생각했을 때,
2번은 1바이트씩 돌아가므로 50바이트만으로도 동작시킬 수 있다.


64비트 기반 프로그래밍

: LLP64(Windows), LP64(Linux)를 고려해준다.
64비트 시스템에 맞게 자료형을 재구성하자.

모델charshortintlongpointer
LLP64 (Windows)1 Byte2 Byte4 Byte4 Byte8 Byte

하지만,,
32비트 시스템과의 호환성을 위해서인지, 포인터를 빼고는 다를 바가 없다.

그냥 포인터 = 8Byte. 이것만 기억하장.

포인터 != 4 Byte 의 예제 !

#include <stdio.h>
int main()
{
	int arr[10] = {0, };
    int arrVal = (int)arr;
    printf("pointer : %d\n", arrVal);
    return 0;
}

arr = 포인터 = 8Byte.
근데 int arrVal = (int)arr; 이걸 보면, 강제 형변환 하는 부분에서
8바이트 -> 4바이트로 형변환 하는거라 문제가 생긴다.

모든 경우는 아니고,
8Byte짜리로 표현한 주소인데 실제 주소가 4Byte만으로도 표현이 되었다면,
4바이트로 캐스팅해도 괜찮다.
하지만 배열이 할당된 위치가 4바이트 이상이었다면 데이터 손실이 발생될 수 있다.

사실 이외에도 문제될 가능성이 높기 때문에 이러한 형변환은 피하도록 하자.


Polymorphic (다형적) 자료형

: 다형적 특성을 지니는 자료형

Windows에서 사용하는 대표적인 Polymorphic 자료형 예제

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

UINT_PTR를 예시로 들 때,
64비트 기반이라면 unsigned __int64 (64비트 int )로 처리,
32비트 기반이라면 unsigned int (32비트 int)로 처리된다.

예제 2

val1과 val2의 메모리 상의 거리 차이를 구하는 예제이다.

UINT CalDistance(UINT a, UINT b)
{
	return a - b;
}

int _tmain()
{
	INT val1 = 10;
    INT val2 = 20;
    _tprintf(_T("Position %d , %d\n"), (UINT)&val1, (UINT)&val2);
    _tprintf(_T("distance : %d\n"), CalDistance((UINT)&val1, (UINT)&val2));
    return 0;
}

UINT = 4바이트.
64비트 시스템에서는 적절히 계산하기 힘들다.

이 상황에서 Polymorpic 자료형을 사용하면 좋다.

#ifdef(_WIN64)
    typedef unsigned __int64 UINT_PTR;
#else
    typedef unsigned int UINT_PTR;
#endif

만약 여기서 UINT대신 UINT_PTR를 사용했다면,
64기반에서는 UINT_PTR이 64비트로 해석되기 때문에 적절히 계산된다.

UINT_PTR이라는 것 자체가 포인터가 아니라, 포인터 연산에 활용하기 위한 자료형이다.

profile
우하하

0개의 댓글