Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga

포인터 라는것은 메모리 주소를 말합니다.

char 포인터나 int 포인터 그리고 void 포인터는 바이트 크기가 다른게 아닙니다.

32비트 프로그램의 경우 모두 32비트=4바이트 크기입니다.

64비트 프로그램의 경우 모두 64비트=8바이트 크기 입니다.

본래 메모리 주소는 39비트 입니다. 그리고 가상주소로 48비트 까지 확장 됩니다.

하지만 CPU가 산술 연산에 제공하는 비트 크기가 32비트 이다보니 39비트는 다루기 힘들어서

32비트 프로그램은 32비트 포인터로 제한한것 입니다.

64비트 프로그램은 충분한 연산 능력을 확보 했지만 CPU가 제공하는 비트수 보다 많아서 결국 48비트까지 제한됩니다.

void 포인터나 int 포인터는 메모리 주소가 가르키는 곳에

존재하는 데이터가 어떤 형식이냐를 컴파일러에게 알려주는것 입니다.

2018.06.25.

기타

[C언어]포인터 변수의 크기는 4바이트? 아니다!

"뇌를 자극하는 C프로그래밍" 이라는 책에서 "모든 포인터 변수의 크기는 4바이트"라고 강조한다.

저 문구의 의미로는 double*, int*, char*와 같이 각각의 포인터변수들의 크기는 모두 4바이트로 같다는 의미이다.

하지만 이는 32bit의 설정으로 컴파일을 했을 때의 결과로, 컴파일 설정이 64bit인 경우엔 포인터변수들의 크기는 4바이트가 아니다.

(64bit의 컴파일러에서 포인터 변수의 크기가 8바이트이며 , 16bit의 컴파일러에서는 2바이트이다.)

C언어의 컴파일 시, 운영체제의 bit가 아닌 컴파일러의 bit에 따라서 포인터 변수의 크기가 달라짐 참조 링크 :

http://stackoverflow.com/questions/16823752/why-size-of-void-pointer-is-4-on-windows-64-bit-platform

Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga

Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga

위와 같이 필자가 간단하게 코딩해서 포인터 변수들의 크기를 살펴 보았다.

visual stdio 2008로 컴파일을 간단하게 해 보았는데, x32로 컴파일해서 포인터 변수가 4바이트로 나온다. (운영체제는 64bit window 7)

즉, 64bit의 운영체제로 컴파일을 한다고 포인터 변수가 8바이트가 아니고, 컴파일러의 설정에 따라 포인터변수의 크기가 바뀐다.

(64bit의 운영체제는 32bit의 컴파일러를 돌릴수 있음.)

만일 x32로 컴파일 하지않고 x64로 컴파일하게 된다면 포인터 변수의 크기는 8바이트로 바뀔 것이다.

< Visual stdio 로 64bit build를 하기 위한 설정 방법 참조 링크 : http://dream-cy.tistory.com/36 >

Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga

1. 포인터 변수의 크기는 4바이트로 고정된 것이 아니다.

2. 운영체제의 bit수가 포인터 변수의 크기에 영향을 미치는 것은 아니다.

3. 포인터 변수의 크기(double *,char *, int*)의 크기는 컴파일러의 상황에 따라 다르다

-32bit로 컴파일 시, 4바이트로 모두 같고

-64bit로 컴파일 시, 8바이트로 모두 같다.

4. 64bit의 운영체제에서 32bit로 컴파일 시 포인터변수의 크기가 4바이트로 나타난다.

5. 64bit의 운영체제에서 64bit로 컴파일 시 포인터변수의 크기가 8바이트로 나타난다.

  <-운영체제에 따라 포인터변수의 크기가 정해지는 것이 아님

■ void형 포인터란 무엇인가?

      - 자료형에 대한 정보가 제외된, 주소 정보를 담을 수 있는 형태의 변수야.

      - 포인터 연산, 메모리 참조와 관련된 일에 활용 할 수 없어.

      보통은 void 포인터라고 많이 얘기들을 해.

      포인터는 무조건 주소값을 저장할 수 있는 변수야.

      void형 포인터는 일반적인 포인터와 달리 저장할 수 있는 주소값의 형태가 제한되어 있지 않아.

      예를 들어.........

             int형 포인터 a가 있다고 가정하자. int *a 는 int형 변수만 저장할 수 있겠지.

             포인터라 할지라도 저장할 수 있는 주소값의 형태는 제한적이라는 거야.

             char형 포인터 b는 char *b .... 이 녀석은 char형 변수의 주소값만 저장할 수 있겠지.

             void *c

             이러한 형태의 void 포인터 c는 어떠한 형태든지 담을 수 있는 상자와 같애.

             즉, int, char, int형 포인터의 주소값 등등 다 저장가능하다는 거야.

                  타입정보에 상관없이 어떠한 데이터이든 그 데이터가 올라가있는 메모리의 주소값을 다 담을 수 있다라는 거야.

                  이유는?

                           void형 포인터는 자료형에 대한 정보가 제외되어 있기 때문에 가능하다라는 거야.

                           휠씬 유용할까?

                                  아니야... 휠씬 제한적인 기능만 가진다는 거야.

                                               예를 들어.......

                                                            int *a 에서 a라는 포인터는 4byte를 참조해.

                                                            char *b 에서 a라는 포인터는 abyte를 참조해.

                                                             위의 포인터들은 포인터 연산시 얼마씩 증가할지를 어떤 타입의 데이터를 가리키냐

                                                             로 판단이 가능하다는 거야.

                                                             이에 반해 void 포인터는 타입정보가 빠져있어.

                                                             그래서 메모리 공간참조, 포인터 연산 같은게 불가능하다는 거야.

                                  아래 우측의 코드는 에러를 발생시켜.

                                   *vp = 20; 은 void포인터가 가르키는 메모리 공간을 참조해서 값을 20을 넣으라는 거야.

                                                    근데 몇바이트를 참조해야 할지 막연해. 

                                                    왜냐면 void 포인터는 주소값만 가지지 메모리 공간의 자료형 정보는 담지 않거든.

                                   결국 void 포인터는 모든 타입의 주소값 저장이 가능하지만

                                                              포인터 연산, 메모리 참조와 관련된 일에 할용 할 수 없다는 거야.

                                   어디서 활용할까?

                                             다음 파트에 malloc 이라는 함수에서 '동적 할당'을 공부하면서 이야기 해보자.

Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga

■ main 힘수의 인자 전달

      아래 좌측의 코드 중에서 독특한 부분이 보일거야.

      이제껏 우리가 써온 메인함수는 int main(void) 라고 해서 메인함수는 인자값을 받지 않겠다고 썼지.

      근데 아래 메인함수의 매개변수를 보면.........

                    int argc, char **argv    라는 부분말야.

      아래 코드를 실행한다고 하면 main_arg.exe 라는 파일이 생성될꺼야.

      실행파일이 존재하는 위치가 c:\> 라고 하면 c:\>main_arg 를 치고 엔터를 치면 실행이 되지.

      실제로 이 실행파일에 있는 메인함수를 호출하기 전에 하는 일이 있어.

                1) 문자열을 메모리 공간에 만들어서 올려.

                    c:\> 에서 입력한 "main_arg"를 문자열 상수로 만들어서 메모리 공간에 올린다는 거야.

                2) 문자열 상수의 주소값을 배열에 저장해.

                    지금은 문자열이 하나니까 배열이 하나있다고 가정할깨. 각각의 요소가 char형 포인터.... char* 로 만들어서

                    이 배열이 "main_arg"를 가르키게끔 구성을 해.

                3) 이제 메인함수를 호출을 하지.

                    매개변수가 void라면 아무런 정보도 전달이 되지 않아.

                    그런데, 아래에서와 같이 int argc char **argv  와 같이 설정할 경우에 어떤 일이 벌어질까?

                               첫 번째 인자 int argc 에 생성된 문자열의 갯수를 전달해... 하나.. 즉 1일 전달해.

                               두 번째 인자 **argv 는 char형 싱글포인터형 주소값을 가르킬 수 있게끔 구성되어 있어.

                               char형 싱글 포인터형 주소값이 argv로 전달된다는 거지.

                               main_arg가 저장된 배열의 첫 번째 요소. 즉 주소값을 가르키게 되지. 0x10 이라 가정하자.

                               싱글 포인터를 저장하기 위한 더블 포인터 **argv 라는 거야.

                    그럼 int argc, char **argv 를 통해 실제 문자열이 저장된 곳을 참조하는 것이 가능해 진다는 거야.

Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga

        ▶ 아래 그림 우측을 보고 다시 이야기 해보자.

            이번에는 실행파일이 c:\>test 라는 폴더에 있다고 가정하자.

            근데.....

                 c:\test>main_arg abcd 1234  이라고 실행파일 옆에 못보던 녀석들이 왔어?

                                 main 함수를 호출하기 이전에 3개의 문자열 상수를 만든다는 거야. 그림에서 확인해봐.

                                 그리고 3개의 문자열 상수를 저장하기 위한 길이가 3인 배열이 생성되지.

                                 각각의 요소는 당연히 char형 포인터 변수가 되겠지.

                                 첫 번째 배열 요소는 "main_arg"를 가르키고

                                 두 번째 배열 요소는 "a b c d"를 가르르키고

                                 세 번째 배열 요소는 "1 2 3 4"를 가르키지.

                                 이런 과정은 메인함수가 호출되기 전에 메모리 공간에 구성되는 거야.

                                 입력된 문자열의 갯수는 총 3개야.

                                 이제 메인함수를 호출하게 되면.......

                                        argc 의 값으로 3을 전달하고 argv라는 포인터에 arr이라는 주소값을 전달한다는 거야.

                                        주의 !!!!!!

                                               arr[0]의 값을 전달하는 것이 아니라 arr 이라는 배열 요소의 주소값을 전달하는 거야.

                                        따라서 메인함수가 호출되면서 argc는 3, argc는 arr[0]를 가르키는 형태가 되지.

                                                  arr이라는 배열도 arr[0]를 가르키는 거고 말야.

                                                  결국 argv 와 arr 도 같은 의미를 지니게 되는 거지.

                                        코드에서 for문을 보면 (i=0; i<argc; i++) 라는 조건식을 썼어.

                                        무슨일을 하라는 걸까?

                                                     각각이 가르키는 문자열을 출력하라는 뜻이지.

                                         메인함수를 호출하면서 인자로서 문자열을 전달해야 하는 상황은 아주 자주 등장해.

                                         반드시 기억을 해둬야 하는 내용이지.


Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga
     

      ▶ 예제를 통해 다시 알아보자.

아래 코드를 실행해보면.....

Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga
 

아래와 같은 결과값이 나오지. 이게 끝이 아니고......      

실제 실행파일이 있는 곳에서 문자열을 전달해보자고....

Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga

아래의 경우를 보면 argc 는 3이 될것이고 argv 는 배열의 첫 번째 요소니까 Hello의 주소값을 지니게 되겠지.

for 문 루프를 돌면서 각각의 배열요소를 출력하는 형태가 되겠지.

위의 그림과 매핑시켜서 이해해보도록 하자.


Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga

다시 Hello 라고만 실행를 해보면 아래의 결과가 나오지. 실행파일의 이름자체로 문자열로 구성된다는 거야.

Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga

그럼 이번에는 문자열을 구분짓는 기준은 ???

               abcd 와 1234 를 하나로 묶고 싶다면 ???

답은 큰따음표를 사용해서 묶어 버리면 된다는 거야.  총 문자열이 2개의 문자열을 컴파일러가 인식하지.

공백도 문자열로 인식시키기 위해 큰따음표를 사용했어.


       

Void 포인터는 몇 바이트 인가 - Void pointeoneun myeoch baiteu inga