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.
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 :virtualpublic 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.
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
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.
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.
@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.
"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.
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.
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.
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.
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.
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.
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.
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.
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.
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
char888short161616int643232long646432longlong646464
pointer 646464
Respostas:
A garantia que você recebe é essa
sizeof(char) == 1
. Não há outras garantias, incluindo nenhuma garantia dissosizeof(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.
fonte
Mesmo em uma plataforma simples de x86 de 32 bits, você pode obter vários tamanhos de ponteiro; tente isso por exemplo:
No Visual C ++ 2008, recebo 4, 12 e 8 para os tamanhos da função ponteiros para membro.
Raymond Chen falou sobre isso aqui .
fonte
Apenas mais uma exceção à lista já publicada. Em plataformas de 32 bits, os ponteiros podem levar 6, não 4 , bytes:
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
fonte
se você estiver compilando para uma máquina de 64 bits, pode ser 8.
fonte
sizeof(char*)==1
,? Você tem certeza? Você não quer dizersize(char)==1
?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.
fonte
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^32
espaço de endereço e máquinas de 64 bits podem ter2^64
espaç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.
fonte
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.
fonte
void*
echar*
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*
eint*
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.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.
fonte
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.
fonte
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.
fonte
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
, eunsigned 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 "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.
fonte
Não, o tamanho de um ponteiro pode variar dependendo da arquitetura. Existem inúmeras exceções.
fonte
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.
fonte
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.
fonte
No Win64 (Cygwin GCC 5.4) , vamos ver o exemplo abaixo:
Primeiro, teste a seguinte estrutura:
O código de teste está abaixo:
A saída está abaixo:
Você pode ver que em 64 bits,
sizeof(pointer)
é8
.fonte
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.
fonte
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.
Fonte: https://stackoverflow.com/a/384672/48026
fonte