실수부 포인터
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가 출력되지 않는다.
'개발자과정준비 > C' 카테고리의 다른 글
[C] 배열 - 2 (배열과 포인터, 문자열) (0) | 2020.10.27 |
---|---|
[C] 배열 - 1 (배열의 선언과 초기화, 문자열) (0) | 2020.10.22 |
[C] 포인터 - 3 (포인터 초기화, 포인터 연산) (0) | 2020.10.20 |
[C] 포인터 - 2 (0) | 2020.10.15 |
[C] 포인터 - 1 (0) | 2020.10.14 |