O tamanho de (algum ponteiro) é sempre igual a quatro?

227

Por exemplo: sizeof(char*)retorna 4. Como é que int*, long long*, tudo o que eu tentei. Há alguma exceção a isso?

Joel
fonte
51
Por que marcar isso? Boa pergunta para qualquer iniciante.
Martin York
2
Suspeito que outra questão esteja oculta nesta: "Qual é o tamanho?" ou pode ser "Por que sizeof <qualquer ponteiro> == 4? O que há de tão especial em 4?". Estou certo?
2
Bem, isso depende da sua plataforma. A maioria das implementações compartilha o mesmo tamanho para todos os tipos de ponteiros em uma plataforma específica.
Phoeagon 16/05

Respostas:

194

A garantia que você recebe é essa sizeof(char) == 1. Não há outras garantias, incluindo nenhuma garantia disso sizeof(int *) == sizeof(double *).

Na prática, os ponteiros serão do tamanho 2 em um sistema de 16 bits (se você puder encontrar um), 4 em um sistema de 32 bits e 8 em um sistema de 64 bits, mas não há nada a ganhar com a confiança em um determinado Tamanho.

David Thornley
fonte
96
E 3 bytes em um sistema de 24 bits. Sim, eu trabalhei em um. Bem-vindo ao mundo dos dispositivos incorporados.
dwj
30
Também trabalhei em sistemas de 16 bits com ponteiros de 20 bits. Eu deveria ir ver qual o tamanho de retorno nesse caso ...
Juiz Maygarden
5
@monjardin: IIRC, o 8086 era assim. Havia um endereço de 16 bits e um registro de segmento de 4 bits. Acredito que um ponteiro "NEAR" normal tenha 16 bits e um ponteiro declarado como "FAR" tenha mais, provavelmente 24, embora não tenha certeza.
Rmeador 29/12/08
18
outra garantia é que sizeof (char *) == sizeof (void *), porque eles precisam ter as mesmas representações (objeto [tamanho] e valor [conjunto de bits relevantes para seu valor])
Johannes Schaub - litb
7
Como a pergunta solicita exceções, deve-se notar que os ponteiros de função de membro não estático costumam ter um tamanho diferente dos ponteiros normais e também variam de acordo com a plataforma, o tipo etc. Além disso, com +1.
John5342
36

Mesmo em uma plataforma simples de x86 de 32 bits, você pode obter vários tamanhos de ponteiro; tente isso por exemplo:

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;
}

No Visual C ++ 2008, recebo 4, 12 e 8 para os tamanhos da função ponteiros para membro.

Raymond Chen falou sobre isso aqui .

Eclipse
fonte
4
Ponteiros para funções-membro são uma verdadeira dor. É lamentável que nem todos os compiladores gostem do compilador Digital Mars C ++, que retorna 4 em todos os casos.
18710 dalle
gcc 4.72 print all 8 ... Isso é indefinido no padrão c ++?
Gob00st
2
@ Gob00st: A única coisa definida é que char é 1. Outros tipos podem ter qualquer tamanho relevante para esse compilador. Não há requisito para consistência entre esses tipos de ponteiro.
Eclipse em
ok obrigado. Não é de admirar que o gcc e o VC tenham uma implementação diferente.
Gob00st
5
@Eclipse sim, há: char <= curto <= int <= longa <= long long
Cole Johnson
30

Apenas mais uma exceção à lista já publicada. Em plataformas de 32 bits, os ponteiros podem levar 6, não 4 , bytes:

#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;
}

Se você compilar esse programa com o Open Watcom e executá-lo, obterá 6, porque os indicadores remotos que ele suporta consistem em valores de deslocamento de 32 bits e segmento de 16 bits

dmityugov
fonte
5
Não segmento, mas selector vez - não é uma parte do endereço de memória, mas uma entrada de índice no LDT ou GDT e tem algumas bandeiras de acesso
Roee Shenberg
1
Por que existem segmentos e deslocamentos em x86 enquanto o espaço de endereço é plano?
phuclv
@ LưuVĩnhPhúc Porque poupa espaço para o caso muito comum de ponteiros próximos, que pode ser codificado mais curto.
Christopher Creutzig
1
@ChristopherCreutzig, que significa que os segmentos são usados ​​para estender o espaço de endereço, como o PAE?
585 phuclv # 03
@ LưuVĩnhPhúc Já faz muito tempo que faço montagem em qualquer coisa de 32 bits. A parte que me lembro é que você pode economizar espaço para ponteiros apontando para o código que você possui. Além disso, nem todas as arquiteturas de 32 bits - certamente nem todas baseadas no x86 - usam um modelo de memória plana. Veja, por exemplo, tenouk.com/Bufferoverflowc/Bufferoverflow1a.html para mais algumas discussões sobre isso, embora, como eu disse, já tenha passado algum tempo e não posso garantir nada.
Christopher Creutzig
24

se você estiver compilando para uma máquina de 64 bits, pode ser 8.

FryGuy
fonte
2
Embora esse seja geralmente o caso, não é necessariamente verdade. Por exemplo, se você estiver compilando em uma máquina de 64 bits em que o tamanho da palavra é de 64 bits, sizeof (char *) provavelmente será 1. Sem mencionar os tipos de ponteiros mais exóticos, mesmo nas máquinas comuns, como Eclipse e dmityugov escrever.
Kaz Dragon
@KazDragon sizeof(char*)==1,? Você tem certeza? Você não quer dizer size(char)==1?
Aaron McDaid
3
@AaronMcDaid Eu realmente quis dizer sizeof (char *). sizeof (char) é sempre 1. Mas se a palavra da máquina for de 64 bits e o ambiente de desenvolvimento for implementado de forma que CHAR_BITS = 64, é possível que um ponteiro caiba no mesmo espaço que um char e, portanto, também é 1.
Kaz Dragon
não é verdade em x32-abi sites.google.com/site/x32abi
phuclv
1
@KazDragon Estou construindo (muito lentamente, quando não procrastinar) uma máquina com palavras de 16 bits e sem endereçamento de bytes. Embora não possa executar C de qualquer maneira.
user253751
17

Tecnicamente falando, o padrão C apenas garante esse sizeof (char) == 1, e o restante depende da implementação. Mas nas arquiteturas modernas x86 (por exemplo, chips Intel / AMD) é bastante previsível.

Você provavelmente já ouviu processadores descritos como sendo de 16 bits, 32 bits, 64 bits etc. Isso geralmente significa que o processador usa N bits para números inteiros. Como os ponteiros armazenam endereços de memória, e os endereços de memória são inteiros, isso indica efetivamente quantos bits serão usados ​​para os ponteiros. sizeof é geralmente medido em bytes; portanto, o código compilado para processadores de 32 bits reportará o tamanho dos ponteiros como 4 (32 bits / 8 bits por byte) e o código para processadores de 64 bits informará o tamanho dos ponteiros como 8. (64 bits / 8 bits por byte). É daí que vem a limitação de 4 GB de RAM para processadores de 32 bits - se cada endereço de memória corresponder a um byte, para endereçar mais memória, você precisará de números inteiros maiores que 32 bits.

Joseph Garvin
fonte
"Você provavelmente já ouviu processadores descritos como sendo de 16 bits, 32 bits, 64 bits etc. Isso geralmente significa que o processador usa N bits para números inteiros." -> Estou tendo uma máquina de 64 bits, mas o sizeof (int) é de 4 bytes. Se sua afirmação for verdadeira, como isso pode ser possível ?!
precisa saber é o seguinte
6
@SangeethSaravanaraj: Para compatibilidade com versões anteriores com código de 32 bits, eles decidiram que o int continua com 4 bytes e exige que você opte por usar o tipo de 8 bytes especificando 'long'. long é realmente o tamanho da palavra nativa em x86-64. Uma maneira de ver isso é que normalmente os compiladores vão preencher suas estruturas para torná-las alinhadas por palavras (embora possa haver arquiteturas onde o tamanho e o alinhamento das palavras não estejam relacionados), por isso, se você criar uma estrutura com um int (32 bits), e chame sizeof (), se você receber 8, você sabe que está preenchendo o tamanho das palavras de 64 bits.
31712 Joseph Garvin
@SangeethSaravanaraj: Observe que teoricamente o tamanho da palavra nativa da CPU e o que o compilador decide 'int' pode ser arbitrariamente diferente, é apenas uma convenção que 'int' seja o tamanho da palavra nativa antes da chegada do x86-64, onde é longo para facilitar a compatibilidade com versões anteriores.
31712 Joseph Garvin
Obrigada pelo esclarecimento! :)
Sangeeth Saravanaraj
7

O tamanho do ponteiro depende basicamente da arquitetura do sistema em que é implementado. Por exemplo, o tamanho de um ponteiro em 32 bits é de 4 bytes (32 bits) e 8 bytes (64 bits) em máquinas de 64 bits. Os tipos de bits em uma máquina nada mais são do que o endereço de memória que ela pode ter. Máquinas de 32 bits podem ter 2^32espaço de endereço e máquinas de 64 bits podem ter 2^64espaços de endereço até . Portanto, um ponteiro (variável que aponta para um local de memória) deve ser capaz de apontar para qualquer endereço de memória ( 2^32 for 32 bit and 2^64 for 64 bit) que uma máquina mantenha.

Por esse motivo, vemos que o tamanho de um ponteiro é de 4 bytes em uma máquina de 32 bits e de 8 bytes em uma máquina de 64 bits.

Rndp13
fonte
6

Além das diferenças de 16/32/64 bits, coisas ainda mais estranhas podem ocorrer.

Houve máquinas em que sizeof (int *) terá um valor, provavelmente 4, mas onde sizeof (char *) é maior. Máquinas que endereçam naturalmente palavras em vez de bytes precisam "aumentar" ponteiros de caracteres para especificar qual parte da palavra você realmente deseja para implementar corretamente o padrão C / C ++.

Isso agora é muito incomum, pois os projetistas de hardware aprenderam o valor da endereçamento de bytes.

Darron
fonte
4
O compilador C para máquinas de vetor Cray, como o T90, faz algo semelhante. Os endereços de hardware são 8 bytes e apontam para palavras de 8 bytes. void*e char*são manipulados em software e aumentados com um deslocamento de 3 bits dentro da palavra - mas como na verdade não existe um espaço de endereço de 64 bits, o deslocamento é armazenado nos 3 bits de alta ordem dos 64 bits. palavra. Assim, char*e int*são do mesmo tamanho, mas têm diferentes representações internas - e código que pressupõe que os ponteiros são "realmente" apenas números inteiros pode deixar mal.
Keith Thompson
5

Ponteiros de 8 e 16 bits são usados ​​na maioria dos microcontroladores de perfil baixo. Isso significa que todas as máquinas de lavar, micro, geladeira, TVs mais antigas e até carros.

Você poderia dizer que isso não tem nada a ver com a programação do mundo real. Mas aqui está um exemplo do mundo real: Arduino com 1-2-4k de ram (dependendo do chip) com ponteiros de 2 bytes.

É recente, barato, acessível para todos e vale a pena codificar.

Kobor42
fonte
4

Além do que as pessoas disseram sobre sistemas de 64 bits (ou qualquer outra coisa), existem outros tipos de ponteiros que não o ponteiro para o objeto.

Um ponteiro para membro pode ter quase qualquer tamanho, dependendo de como são implementados pelo seu compilador: eles não são necessariamente do mesmo tamanho. Tente um ponteiro para membro de uma classe POD e, em seguida, um ponteiro para membro herdado de uma das classes base de uma classe com várias bases. Que divertido.

Steve Jessop
fonte
3

Pelo que me lembro, é baseado no tamanho de um endereço de memória. Portanto, em um sistema com um esquema de endereços de 32 bits, sizeof retornará 4, já que são 4 bytes.

Will Mc
fonte
4
Não existe esse requisito. Não há nem mesmo um requisito que sizeof (int não assinado) == sizeof (int assinado). O tamanho de um ponteiro para um int sempre será, por definição, sizeof (int *), para um char sizeof (char *) etc. Basear-se em qualquer outra suposição é uma má idéia para portabilidade.
Mihai Limbășan
Ah, eu vejo agora. Obrigado pela informação.
Will Mc
1
Ainda pode retornar 2, se CHAR_BIT for 16. sizeof () conta em número de caracteres, não em octetos.
MSalters 06/04/09
5
@ Mii: No C ++ sizeof (unsigned int) == sizeof (signed int), esse requisito é encontrado em 3.9.1 / 3. "Para cada um dos padrão inteiro assinado tipos, existe um tipo inteiro sem sinal padrão correspondente (mas diferente): unsigned char, unsigned short int, unsigned int, unsigned long int, e unsigned long long int, cada um dos quais ocupa a mesma quantidade de armazenamento e tem os mesmos requisitos de alinhamento como a correspondente inteiro assinado tipo "
Ben Voigt
3

Em geral, sizeof (praticamente qualquer coisa) muda quando você compila em plataformas diferentes. Em uma plataforma de 32 bits, os ponteiros são sempre do mesmo tamanho. Em outras plataformas (sendo o exemplo óbvio de 64 bits) isso pode mudar.

Sean Reilly
fonte
3

Não, o tamanho de um ponteiro pode variar dependendo da arquitetura. Existem inúmeras exceções.

Juiz Maygarden
fonte
3

O tamanho do ponteiro e int é de 2 bytes no compilador Turbo C na máquina Windows de 32 bits.

Portanto, o tamanho do ponteiro é específico do compilador. Mas geralmente a maioria dos compiladores é implementada para suportar variáveis ​​de ponteiro de 4 bytes em 32 bits e variável de ponteiro de 8 bytes em máquinas de 64 bits).

Portanto, o tamanho do ponteiro não é o mesmo em todas as máquinas.

finalsemester.co.in
fonte
2

A razão pela qual o tamanho do seu ponteiro é de 4 bytes é porque você está compilando para uma arquitetura de 32 bits. Como FryGuy apontou, em uma arquitetura de 64 bits você veria 8.

Will Bickford
fonte
2

No Win64 (Cygwin GCC 5.4) , vamos ver o exemplo abaixo:

Primeiro, teste a seguinte estrutura:

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

struct test_struc{
    char a, b;
};

O código de teste está abaixo:

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;    

A saída está abaixo:

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

Você pode ver que em 64 bits, sizeof(pointer)é 8.

Jayhello
fonte
1

Um ponteiro é apenas um contêiner para um endereço. Em uma máquina de 32 bits, seu intervalo de endereços é de 32 bits; portanto, um ponteiro sempre terá 4 bytes. Em uma máquina de 64 bits, se você tiver um intervalo de endereços de 64 bits, um ponteiro terá 8 bytes.

Ed S.
fonte
1
Em uma máquina de 32 bits com bytes de 32 bits, sizeof (char *) pode ser 1.
Robert Gamble
"... com bytes de 32 bits". Eu não sabia que essas coisas existiam ... imagine isso.
30868 Ed S.
1
Em um pato de 32 bits, sizeof (char *) retorna PI
Adriano Varoli Piazza
0

Apenas por questões de integridade e interesse histórico, no mundo de 64 bits havia diferentes convenções de plataforma nos tamanhos de tipos longos e longos, denominados LLP64 e LP64, principalmente entre sistemas do tipo Unix e Windows. Um padrão antigo chamado ILP64 também tornou int = 64 bits de largura.

A Microsoft manteve o LLP64 em que longlong = 64 bits de largura, mas permaneceu em 32, para facilitar a portabilidade.

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

Fonte: https://stackoverflow.com/a/384672/48026

Hernán
fonte