sizeof (일부 포인터)는 항상 4와 같은가요?


227

예를 들어 sizeof(char*)로는 않습니다 4. 반환 int*, long long*내가 해봤 모든 것을. 이것에 대한 예외가 있습니까?


51
왜 이것을 표시하지 않습니까? 초보자에게 좋은 질문입니다.
Martin York

2
다른 질문이이 질문에 숨겨져있는 것 같습니다. "크기는 얼마입니까?" 또는 "왜 sizeof <any pointer> == 4입니까? 4의 특별한 점은 무엇입니까?" 내가 맞아?

2
글쎄, 그것은 당신의 플랫폼에 달려 있습니다. 대부분의 구현은 특정 플랫폼의 모든 종류의 포인터에 대해 동일한 크기를 공유합니다.
phoeagon

답변:


194

당신이 얻는 보증은입니다 sizeof(char) == 1. 보증 없음을 포함하여 다른 보증은 없습니다 sizeof(int *) == sizeof(double *).

실제로, 포인터는 16 비트 시스템에서 크기 2 (하나를 찾을 수있는 경우), 32 비트 시스템에서 4 개, 64 비트 시스템에서 8입니다. 크기.


96
그리고 24 비트 시스템에서 3 바이트. 예, 저는 한 가지 일을했습니다. 임베디드 장치의 세계에 오신 것을 환영합니다.
dwj

30
나는 20 비트 포인터로 16 비트 시스템에서 일했다. 이 경우 어떤 크기의 수익이 발생하는지 보러 가야합니다.
Maygarden Judge

5
@ monjardin : IIRC, 8086은 그랬습니다. 16 비트 주소와 4 비트 세그먼트 레지스터가있었습니다. 확실하지는 않지만 일반적인 "NEAR"포인터는 16 비트이고 "FAR"로 선언 된 포인터는 24 개일 것입니다.
rmeador

18
또 다른 보장은 sizeof (char *) == sizeof (void *)입니다. 동일한 표현 (객체 [size] 및 값 [값과 관련된 비트 집합] 표현)을 가져야하므로
Johannes Schaub-litb

7
질문은 예외를 요구하기 때문에 비 정적 멤버 함수 포인터는 보통 일반 포인터와 크기가 다르고 플랫폼, 유형 등에 따라 다릅니다. +1 이외의 것입니다.
John5342

36

일반 x86 32 비트 플랫폼에서도 다양한 포인터 크기를 얻을 수 있습니다. 예를 들어 다음을 시도해보십시오.

struct A {};

struct B : virtual public A {};

struct C {};

struct D : public A, public C {};

int main()
{
    cout << "A:" << sizeof(void (A::*)()) << endl;
    cout << "B:" << sizeof(void (B::*)()) << endl;
    cout << "D:" << sizeof(void (D::*)()) << endl;
}

Visual C ++ 2008에서 포인터 대 멤버 함수의 크기에 대해 4, 12 및 8을 얻습니다.

Raymond Chen은 이에 대해 이야기 했습니다 .


4
멤버 함수에 대한 포인터는 정말 고통입니다. 불행히도 모든 컴파일러가 Digital Mars C ++ 컴파일러를 좋아하는 것은 아니며 모든 경우에 4를 반환합니다.
dalle

gcc 4.72 print all 8 ... 이것은 C ++ 표준에 정의되어 있지 않습니까?
Gob00st

2
@ Gob00st : 정의 된 유일한 것은 char이 1이라는 것입니다. 다른 유형은 해당 컴파일러와 관련된 크기가 될 수 있습니다. 이 포인터 유형 사이의 일관성에 대한 요구 사항은 없습니다.
Eclipse

알았어 고마워. 그렇다면 gcc와 VC의 구현 방식이 다른 것은 당연하다.
Gob00st

5
@Eclipse 네 있습니다 : char <= short <= int <= long <= long long
Cole Johnson

30

이미 게시 된 목록에 대한 또 다른 예외입니다. 32 비트 플랫폼에서 포인터는 4 바이트가 아닌 6 바이트를 사용할 수 있습니다 .

#include <stdio.h>
#include <stdlib.h>

int main() {
    char far* ptr; // note that this is a far pointer
    printf( "%d\n", sizeof( ptr));
    return EXIT_SUCCESS;
}

Open Watcom으로이 프로그램을 컴파일하고 실행하면 지원되는 멀리 포인터가 32 비트 오프셋 및 16 비트 세그먼트 값으로 구성되므로 6을 얻게됩니다.


5
세그먼트가 아니라 셀렉터가 아닌 메모리 주소의 일부가 아니라 LDT 또는 GDT의 인덱스 항목이며 액세스 플래그가 있습니다
Roee Shenberg

1
주소 공간이 평평한 동안 x86에 세그먼트와 오프셋이있는 이유는 무엇입니까?
phuclv

@ LưuVĩnhPhúc 거의 가까운 포인터의 경우 공간을 절약하기 때문에 더 짧은 인코딩이 가능합니다.
Christopher Creutzig

1
@ChristopherCreutzig는 세그먼트가 PAE와 같은 주소 공간을 확장하는 데 사용된다는 것을 의미합니까?
phuclv

@ LưuVĩnhPhúc 32 비트에 대해 어셈블리를 한 것은 오래되었습니다. 내가 기억하는 부분은 가지고있는 코드를 가리키는 포인터를위한 공간을 절약 할 수 있다는 것입니다. 또한 모든 32 비트 아키텍처가 x86을 기반으로하지는 않지만 플랫 메모리 모델을 사용하는 것은 아닙니다. 예를 들어 tenouk.com/Bufferoverflowc/Bufferoverflow1a.html 을 참조하십시오 .
Christopher Creutzig

24

64 비트 컴퓨터 용으로 컴파일하는 경우 8 일 수 있습니다.


2
이것이 일반적이지만 사실 일 필요는 없습니다. 예를 들어, 단어 크기가 64 비트 인 64 비트 시스템에서 컴파일하는 경우 sizeof (char *)는 아마도 1 일 것입니다. 일반적인 시스템에서도 Eclipse와 같은 더 이국적인 포인터 유형은 말할 것도 없습니다. dmityugov 쓰기.
Kaz Dragon

@KazDragon, sizeof(char*)==1? 확실합니까? 당신은 의미하지 size(char)==1않습니까?
Aaron McDaid

3
@AaronMcDaid 나는 실제로 sizeof (char *)를 의미했습니다. sizeof (char)는 항상 1입니다. 그러나 기계어가 64 비트이고 개발 환경이 CHAR_BITS = 64와 같은 방식으로 구현되면 포인터가 문자와 같은 공간에 맞을 가능성이 있습니다. 또한 1 일
카즈 드래곤


1
@KazDragon 나는 16 비트 단어가 있고 바이트 주소 지정이없는 기계를 (매우 느리게, 미루지 않을 때) 만들고 있습니다. 어쨌든 C를 실행할 수는 없지만.
user253751

17

기술적으로 말하면 C 표준은 sizeof (char) == 1 만 보장하며 나머지는 구현에 달려 있습니다. 그러나 최신 x86 아키텍처 (예 : Intel / AMD 칩)에서는 상당히 예측 가능합니다.

아마도 16 비트, 32 비트, 64 비트 등의 프로세서가 있다고 들었을 것입니다. 이는 일반적으로 프로세서가 정수에 N 비트를 사용함을 의미합니다. 포인터는 메모리 주소를 저장하고 메모리 주소는 정수이므로 포인터에 사용될 비트 수를 효과적으로 알려줍니다. sizeof는 일반적으로 바이트 단위로 측정되므로 32 비트 프로세서 용으로 컴파일 된 코드는 포인터 크기를 4 (32 비트 / 8 비트 당 8 비트)로보고하고 64 비트 프로세서 용 코드는 포인터 크기를 8로보고합니다. (바이트 당 64 비트 / 8 비트). 32 비트 프로세서에 대한 4GB RAM의 한계는 여기서 시작합니다. 각 메모리 주소가 바이트에 해당하는 경우 더 많은 메모리를 처리하려면 32 비트보다 큰 정수가 필요합니다.


"16 비트, 32 비트, 64 비트 등의 프로세서가 있다고 들었을 것입니다. 이는 일반적으로 프로세서가 정수에 N 비트를 사용한다는 것을 의미합니다." -> 64 비트 컴퓨터를 가지고 있지만 sizeof (int)는 4 바이트입니다. 당신의 진술이 사실이라면 어떻게 가능할까요?!
Sangeeth Saravanaraj

6
@SangeethSaravanaraj : 32 비트 코드와의 하위 호환성을 위해 int는 4 바이트로 계속하기로 결정하고 'long'을 지정하여 8 바이트 유형을 사용하도록 선택해야합니다. 실제로는 x86-64의 기본 단어 크기입니다. 이것을 보는 한 가지 방법은 일반적으로 컴파일러가 구조체를 패딩하여 단어를 정렬하도록합니다 (단어 크기와 정렬이 관련이없는 아키텍처가있을 수 있음). 따라서 int (32 비트)로 구조체를 만들면, sizeof ()를 호출하면 8을 다시 얻으면 64 비트 단어 크기로 채워지는 것을 알 수 있습니다.
Joseph Garvin

@SangeethSaravanaraj : 이론적으로 CPU의 기본 단어 크기와 컴파일러에서 'int'로 결정한 내용은 임의로 다를 수 있습니다. x86-64가 나오기 전에 'int'가 기본 단어 크기가되는 것이 관례였습니다. 거꾸로 나침반을 완화하는 것이 길다.
Joseph Garvin

설명 주셔서 감사합니다! :)
Sangeeth Saravanaraj

7

포인터의 크기는 기본적으로 포인터가 구현되는 시스템의 아키텍처에 따라 다릅니다. 예를 들어 32 비트의 포인터 크기는 64 비트 시스템에서 4 바이트 (32 비트) 및 8 바이트 (64 비트)입니다. 머신의 비트 타입은 메모리 주소에 지나지 않습니다. 32 비트 시스템은 2^32주소 공간을 가질 수 있고 64 비트 시스템은 최대 2^64주소 공간을 가질 수 있습니다 . 따라서 포인터 (메모리 위치를 가리키는 변수)는 2^32 for 32 bit and 2^64 for 64 bit머신이 보유한 메모리 주소 ( ) 를 가리킬 수 있어야합니다 .

이러한 이유로 포인터 크기는 32 비트 시스템에서 4 바이트, 64 비트 시스템에서 8 바이트입니다.


6

16/32/64 비트 차이 외에도 이상한 일이 발생할 수 있습니다.

sizeof (int *)가 하나의 값이되는 기계가 있었을 것입니다. 아마도 4 일 것입니다. 그러나 sizeof (char *)는 더 큽니다. 바이트 대신 단어를 자연스럽게 처리하는 기계는 C / C ++ 표준을 올바르게 구현하기 위해 실제로 원하는 단어 부분을 지정하기 위해 문자 포인터를 "증가"해야합니다.

하드웨어 설계자들이 바이트 어 드레서 빌 러티의 가치를 알게되면서 이것은 매우 드문 일입니다.


4
T90과 같은 Cray 벡터 머신 용 C 컴파일러는 비슷한 기능을 수행합니다. 하드웨어 주소는 8 바이트이며 8 바이트 단어를 가리 킵니다. void*char*소프트웨어에서 처리되고, 워드 내 오프셋 3 비트로 증대된다 - 그러나, 실제로는 64 비트 어드레스 공간이 없기 때문에, 상위의 64 비트의 3 비트를 저장 오프셋 워드. 그래서 char*int*같은 크기,하지만 서로 다른 내부 표현 - 그리고 포인터가 "정말"그냥 정수가 심하게 실패 할 것으로 가정합니다 코드를.
키이스 톰슨

5

8 비트 및 16 비트 포인터는 대부분의 로우 프로파일 마이크로 컨트롤러에서 사용됩니다. 이는 모든 세탁기, 마이크로, 냉장고, 구형 TV 및 심지어 자동차를 의미합니다.

이것들은 실제 프로그래밍과 관련이 없다고 말할 수 있습니다. 그러나 실제 예는 다음과 같습니다. Arduino는 1-2 바이트의 램 (칩에 따라 다름)에 2 바이트 포인터가 있습니다.

최근에 저렴하고 누구나 액세스 할 수 있으며 코딩 할 가치가 있습니다.


4

사람들이 64 비트 (또는 기타) 시스템에 대해 말한 것 외에도 객체에 대한 포인터 이외의 다른 종류의 포인터가 있습니다.

포인터-투-멤버는 컴파일러에 의해 구현되는 방식에 따라 거의 모든 크기 일 수 있습니다. 반드시 같은 크기 일 필요는 없습니다. POD 클래스의 포인터 멤버와 여러베이스가있는 클래스의 기본 클래스 중 하나에서 상속 된 포인터 멤버를 시도하십시오. 무슨 재미.


3

내가 기억하는 것에서 메모리 주소의 크기를 기반으로합니다. 따라서 32 비트 주소 체계가있는 시스템에서 sizeof는 4 바이트이므로 4를 반환합니다.


4
그러한 요구 사항은 없습니다. sizeof (unsigned int) == sizeof (signed int)라는 요구 사항조차 없습니다. int에 대한 포인터의 크기는 항상 정의에 따라 sizeof (int *), char sizeof (char *) 등입니다. 다른 가정에 의존하는 것은 이식성에 대한 나쁜 생각입니다.
Mihai Limbășan

아, 지금 봅니다. 정보 주셔서 감사합니다.
Will Mc

1
CHAR_BIT가 16 인 경우 여전히 2를 리턴 할 수 있습니다. sizeof ()는 8 진수가 아닌 문자 수로 계산됩니다.
MSalters

5
@Mihai : C ++ sizeof (unsigned int) == sizeof (signed int)에서이 요구 사항은 3.9.1 / 3에 있습니다. "유형 정수 서명 표준 각각에 대해 대응하는 (그러나 다른) 표준 부호 정수의 형태가 존재한다 : unsigned char, unsigned short int, unsigned int, unsigned long int, 및 unsigned long long int, 이들 각각은 같은 크기의 저장 용량을 차지하고 형 정수 서명 대응 같은 정렬 요건을 갖는다 "
Ben Voigt

3

일반적으로 다른 플랫폼에서 컴파일 할 때 sizeof (거의 모든 것)가 변경됩니다. 32 비트 플랫폼에서 포인터는 항상 같은 크기입니다. 다른 플랫폼 (64 비트가 명백한 예)에서는 이것이 바뀔 수 있습니다.


3

아니요, 포인터의 크기는 아키텍처에 따라 다를 수 있습니다. 수많은 예외가 있습니다.


3

Windows 32 비트 시스템의 Turbo C 컴파일러에서 포인터 및 int의 크기는 2 바이트입니다.

따라서 포인터의 크기는 컴파일러마다 다릅니다. 그러나 일반적으로 대부분의 컴파일러는 32 비트에서 4 바이트 포인터 변수를, 64 비트 시스템에서 8 바이트 포인터 변수를 지원하도록 구현됩니다.

따라서 포인터 크기는 모든 기계에서 동일하지 않습니다.


2

포인터의 크기가 4 바이트 인 이유는 32 비트 아키텍처를 위해 컴파일하기 때문입니다. FryGuy가 지적했듯이 64 비트 아키텍처에서는 8이 표시됩니다.


2

에서 Win64를 (Cygwin에서 GCC 5.4) ,의 예를 아래에 보자 :

먼저 다음 구조체를 테스트하십시오.

struct list_node{
    int a;
    list_node* prev;
    list_node* next;
};

struct test_struc{
    char a, b;
};

테스트 코드는 다음과 같습니다.

std::cout<<"sizeof(int):            "<<sizeof(int)<<std::endl;
std::cout<<"sizeof(int*):           "<<sizeof(int*)<<std::endl;
std::cout<<std::endl;

std::cout<<"sizeof(double):         "<<sizeof(double)<<std::endl;
std::cout<<"sizeof(double*):        "<<sizeof(double*)<<std::endl;
std::cout<<std::endl;

std::cout<<"sizeof(list_node):      "<<sizeof(list_node)<<std::endl;
std::cout<<"sizeof(list_node*):     "<<sizeof(list_node*)<<std::endl;
std::cout<<std::endl;

std::cout<<"sizeof(test_struc):     "<<sizeof(test_struc)<<std::endl;
std::cout<<"sizeof(test_struc*):    "<<sizeof(test_struc*)<<std::endl;    

출력은 다음과 같습니다.

sizeof(int):            4
sizeof(int*):           8

sizeof(double):         8
sizeof(double*):        8

sizeof(list_node):      24
sizeof(list_node*):     8

sizeof(test_struc):     2
sizeof(test_struc*):    8

64 비트에서 sizeof(pointer)is 8입니다.


1

포인터는 주소의 컨테이너 일뿐입니다. 32 비트 시스템에서 주소 범위는 32 비트이므로 포인터는 항상 4 바이트입니다. 64 비트 시스템에서 주소 범위가 64 비트 인 경우 포인터는 8 바이트입니다.


1
32 비트 바이트를 sizeof (숯불 *)가 32 비트 컴퓨터에서 1. 수
로버트 갬블

"... 32 비트 바이트" 나는 그런 것들이 존재한다는 것을 몰랐다.
Ed S.

1
32 비트 오리에서는 sizeof (숯불 *)는 PI를 반환
아드리 Varoli 광장을

0

완전성과 역사적 관심을 위해 64 비트 세계에서 LLP64 및 LP64라는 길고 긴 long 유형의 크기에 대해 주로 Unix 유형 시스템과 Windows간에 서로 다른 플랫폼 규칙이있었습니다. ILP64라는 오래된 표준도 int = 64 비트 폭으로 만들었습니다.

Microsoft는 LLP64를 longlong = 64 비트 너비로 유지했지만 더 쉽게 이식 할 수 있도록 32로 유지했습니다.

Type           ILP64   LP64   LLP64
char              8      8       8
short            16     16      16
int              64     32      32
long             64     64      32
long long        64     64      64
pointer          64     64      64

출처 : https://stackoverflow.com/a/384672/48026

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.