본문으로 바로가기

[C] 포인터 - 4 (실수부 포인터)

category 개발자과정준비/C 2020. 10. 21. 18:28
반응형

실수부 포인터

3.125와 5.0625를 16진수로 바꿔보자.

메모리 영역에서 확인

 

fnum1과 fnum2를 변환하면 40 48 00 00 , 40 a2 00 00  이다. (메모리 영역에는 리틀엔디안이라서 뒤집혀서 나온다)

fnum3는 6이 2를 곱하면서 2진수로 변환할때 정확히 맞아 떨어지지않기때문에 오차가 생겨서 제대로 출력되지 않는다. 

char* 포인터를 이용해서 fnum3에 3.125를 대입해보자.

#include <stdio.h>

int main() {
	float fnum1 = 3.125f;
	float fnum2 = 5.0625f;
	float fnum3 = 123.6f;
	char* chP = (char*)&fnum3;

	printf("%f\n", fnum1);
	printf("%f\n", fnum2);
	printf("%f\n\n", fnum3); // 123.599998 이 출력되는데, 6을 2진수 표현하는데 오차가 생긴다는 뜻
	
	// 3.125f 대입, 3.125는 16진수로 00 00 48 40 이다.
	*chP = 0x00;
	++chP;
	*chP = 0x00;
	++chP;
	*chP = 0x48;
	++chP;
	*chP = 0x40;

	printf("%f\n", fnum3); // 대입이 잘 됬는지 확인해보자.
	// char 포인터로 1바이트 단위로 데이터 영역을 조작할 수 있다
	
}

char* 는 1바이트 단위로 데이터를 다루므로 1바이트씩 대입해주고, ++ 증감연산자를 이용해서 1바이트단위로 다시 대입해주면 된다.

이렇게 리틀엔디안방식으로 3.125를 16진수로 변환한 40 48 00 00 을 00 00 48 40 순으로 대입해주고 출력해보면 3.125가 출력되는 것을 알 수 있다.

 

 

지금까지의 상수나 변수는 전부 스택영역에 저장되는 것을 볼 수 있다.

밑의 예제에서 int a, b, c; 는 변수끼리는 위치가 비슷하다. main, printf, TTTTtest 등의 메서드들도 위치가 거의 비슷한 것을 볼 수 있다. (함수(메서드)는 데이터 영역에있기 때문이다.)

#include <stdio.h>
void TTTtest() 
{
	// 그냥 테스트용으로 만든 메서드
	printf("TTTtest\n");
}
int main() 
{
	// 스택의 대략적인 주소를 알고싶다.
	int a; // stack
	int b; // stack
	int c; // stack


	printf("Stack %p\n", &a);
	printf("Stack %p\n", &b);
	printf("Stack %p\n\n", &c);


	// 함수(메서드)는 데이터영역에 있다.
	// main 이름자체가 주소이다(상수이다)
	// C#에서는 델리게이트
	printf("Code  %p\n", main);  // main의 주소 출력
	printf("Code  %p\n", printf);
	printf("Code  %p\n", scanf_s);
	printf("Code  %p\n", TTTtest); // 임의로 만든 메서드 주소 출력
	printf("Code  %p\n", "Hello World");  // 문자열의 주소 출력
	printf("Code  %p\n\n", "Hello World1");
	//변수는 변수끼리, 메서드는 메서드끼리 주소가 비슷하다.
    // Code 영역은 메서드, 상수가 저장되고, 읽기만 가능하다.

	return 0;
}

 

Stack영역은 변수를 쓰기때문에 읽기, 쓰기(R, W) 둘 다 가능할 것이다.

하지만 Code 영역은 상수와 메서드가 저장되기때문에 읽기(R)만 가능하다.

 

디버깅 모드에서 main함수의 주소값을 확인해보고, 밑의 예제를 살펴보자.

#include <stdio.h>
int main() 
{
	printf("Code  %p\n", main);
	char* p = 0x00415020;
	printf("%02X\n", *p); // *p의 값을 2자리 16진수로 출력

	// *p는 main의 주소인데 읽기만 가능한 코드영역이다.
	// 그래서 수정하려고하면 프로그램이 터질수도있어서 윈도우가 미리 컷하는 것임.
	*p = 0x55;  // 이거 넣는 순간 윈도우가 짤라서 End가 안나옴

	printf("End\n");

	return 0;
}

 

위의 예제에서 main 함수의 주소값을 char*로 지정해주고, *p = 0x55;로 수정하는 예제이다.

보통 쓰기(W)가 가능하면 *p에 0x55가 그대로 대입되면서 printf문의 End가 출력될 것이다.

하지만, Code영역의 데이터들은 읽기(R)만 가능하기때문에 수정하려고하면 위도우가 알아서 끊어버리기때문에 printf문의 End가 출력되지 않는다.

반응형