Apakah sizeof (beberapa pointer) selalu sama dengan empat?

227

Sebagai contoh: sizeof(char*)mengembalikan 4. Seperti halnya int*, long long*, segala sesuatu yang saya sudah mencoba. Apakah ada pengecualian untuk ini?

Joel
sumber
51
Mengapa menandai ini? Pertanyaan bagus untuk pemula.
Martin York
2
Saya menduga ada pertanyaan lain yang disembunyikan dalam pertanyaan ini: "Berapa ukurannya?" atau mungkin "Mengapa sizeof <any pointer> == 4? Apa yang istimewa tentang 4?". Apakah saya benar?
2
Yah, itu tergantung pada platform Anda. Sebagian besar implementasi berbagi ukuran yang sama untuk setiap jenis pointer pada platform tertentu.
phoeagon

Jawaban:

194

Jaminan yang Anda dapatkan adalah itu sizeof(char) == 1. Tidak ada jaminan lain, termasuk tidak ada jaminan itu sizeof(int *) == sizeof(double *).

Dalam prakteknya, pointer akan berukuran 2 pada sistem 16-bit (jika Anda dapat menemukan satu), 4 pada sistem 32-bit, dan 8 pada sistem 64-bit, tetapi tidak ada yang bisa diperoleh dengan mengandalkan pada yang diberikan ukuran.

David Thornley
sumber
96
Dan 3 byte pada sistem 24-bit. Ya, saya pernah mengerjakannya. Selamat datang di dunia perangkat yang disematkan.
dwj
30
Saya telah bekerja pada sistem 16-bit dengan pointer 20-bit juga. Aku harus pergi melihat berapa ukuran pengembalian dalam kasus itu ...
Hakim Maygarden
5
@monjardin: IIRC, 8086 seperti itu. Ada alamat 16 bit dan register segmen 4 bit. Saya percaya pointer "DEKAT" normal adalah 16 bit dan pointer dinyatakan sebagai "JAUH" lebih, mungkin 24, meskipun saya tidak yakin.
rmeador
18
jaminan lain adalah sizeof (char *) == sizeof (void *), karena mereka harus memiliki representasi yang sama (objek [ukuran] dan nilai [set bit yang relevan untuk nilai mereka] representasi)
Johannes Schaub - litb
7
Karena pertanyaannya meminta pengecualian, perlu dicatat bahwa pointer fungsi anggota non-statis sering berbeda ukuran dengan pointer normal dan juga bervariasi berdasarkan platform, jenis, dll. Selain itu +1.
John5342
36

Bahkan pada platform x86 32 bit biasa, Anda bisa mendapatkan berbagai ukuran penunjuk, coba ini sebagai contoh:

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

Di bawah Visual C ++ 2008, saya mendapatkan 4, 12 dan 8 untuk ukuran fungsi pointer-ke-anggota.

Raymond Chen membicarakan hal ini di sini .

Gerhana
sumber
4
Pointer ke fungsi anggota adalah rasa sakit yang nyata. Sangat disayangkan bahwa tidak semua kompiler melakukannya seperti kompiler Digital Mars C ++, yang mengembalikan 4 dalam semua kasus.
dalle
gcc 4,72 cetak semua 8 ... Apakah ini tidak terdefinisi dalam standar c ++?
Gob00st
2
@ Gob00st: Satu-satunya hal yang didefinisikan adalah bahwa char adalah 1. Tipe lain dapat ukuran apa pun yang relevan dengan kompiler itu. Tidak ada persyaratan untuk konsistensi antara jenis pointer ini.
Eclipse
Ok terima kasih. Maka tidak heran gcc & VC memiliki implementasi yang berbeda.
Gob00st
5
@Eclipse ya ada: char <= pendek <= int <= panjang <= panjang panjang
Cole Johnson
30

Hanya pengecualian untuk daftar yang sudah diposting. Pada platform 32-bit, pointer dapat mengambil 6, bukan 4 , byte:

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

Jika Anda mengkompilasi program ini dengan Open Watcom dan menjalankannya, Anda akan mendapatkan 6, karena pointer jauh yang didukungnya terdiri dari nilai segmen 32-bit dan 16-bit

dmityugov
sumber
5
Bukan segmen, melainkan pemilih - ini bukan bagian dari alamat memori, tetapi entri indeks dalam LDT atau GDT dan memiliki beberapa tanda akses
Roee Shenberg
1
Mengapa ada segmen dan offset di x86 sementara ruang alamat datar?
phuclv
@ LưuVĩnhPhúc Karena menghemat ruang untuk kasus yang sangat umum dari pointer dekat, yang dapat disandikan lebih pendek.
Christopher Creutzig
1
@ChristopherCreutzig artinya segmen digunakan untuk memperluas ruang alamat seperti PAE?
phuclv
@ LưuVĩnhPhúc Sudah lama saya melakukan perakitan pada sesuatu yang 32 bit. Bagian yang saya ingat adalah bahwa Anda dapat menghemat ruang untuk pointer yang menunjuk ke kode yang Anda miliki. Juga, tidak semua arsitektur 32 bit - tentu saja tidak semua didasarkan pada x86 - menggunakan model memori datar. Lihat, misalnya, tenouk.com/Bufferoverflowc/Bufferoverflow1a.html untuk diskusi lebih lanjut tentang ini, meskipun, seperti yang saya katakan, sudah lama dan saya tidak dapat menjamin apa pun.
Christopher Creutzig
24

jika Anda mengkompilasi untuk mesin 64-bit, maka mungkin 8.

FryGuy
sumber
2
Meskipun ini biasanya terjadi, belum tentu benar. Misalnya, jika Anda mengkompilasi pada mesin 64-bit di mana ukuran kata adalah 64-bit, maka sizeof (char *) mungkin akan 1. Belum lagi jenis pointer yang lebih eksotis di mesin yang bahkan umum, seperti Eclipse dan dmityugov menulis.
Kaz Dragon
@KazDragon sizeof(char*)==1,? Apakah kamu yakin Bukankah maksud Anda size(char)==1?
Aaron McDaid
3
@AaronMcDaid Aku memang benar-benar berarti sizeof (char *). sizeof (char) selalu 1. Tetapi jika kata mesin Anda 64-bit, dan lingkungan pengembangan Anda diimplementasikan sedemikian rupa sehingga CHAR_BITS = 64, maka ada kemungkinan bahwa pointer cocok di ruang yang sama dengan char dan karenanya akan juga menjadi 1.
Kaz Dragon
itu tidak benar di x32-abi sites.google.com/site/x32abi
phuclv
1
@KazDragon Saya sedang membangun (sangat lambat, ketika tidak menunda-nunda) mesin dengan kata-kata 16-bit dan tanpa alamat byte. Meskipun tidak bisa menjalankan C toh.
user253751
17

Secara teknis, standar C hanya menjamin bahwa sizeof (char) == 1, dan sisanya terserah implementasi. Tetapi pada arsitektur x86 modern (mis. Chip Intel / AMD) cukup dapat diprediksi.

Anda mungkin pernah mendengar prosesor yang digambarkan sebagai 16-bit, 32-bit, 64-bit, dll. Ini biasanya berarti bahwa prosesor menggunakan N-bit untuk bilangan bulat. Karena pointer menyimpan alamat memori, dan alamat memori adalah bilangan bulat, ini secara efektif memberi tahu Anda berapa banyak bit yang akan digunakan untuk pointer. sizeof biasanya diukur dalam byte, jadi kode yang dikompilasi untuk prosesor 32-bit akan melaporkan ukuran pointer menjadi 4 (32 bit / 8 bit per byte), dan kode untuk prosesor 64-bit akan melaporkan ukuran pointer menjadi 8 (64 bit / 8 bit per byte). Di sinilah batasan 4GB RAM untuk prosesor 32-bit berasal - jika setiap alamat memori sesuai dengan satu byte, untuk menangani lebih banyak memori, Anda membutuhkan bilangan bulat yang lebih besar dari 32-bit.

Joseph Garvin
sumber
"Anda mungkin pernah mendengar prosesor yang digambarkan sebagai 16-bit, 32-bit, 64-bit, dll. Ini biasanya berarti bahwa prosesor menggunakan N-bit untuk bilangan bulat." -> Saya memiliki mesin 64-bit tetapi sizeof (int) adalah 4 byte. Jika pernyataan Anda benar, bagaimana mungkin ini terjadi ?!
Sangeeth Saravanaraj
6
@SangeethSaravanaraj: Untuk kompatibilitas mundur dengan kode 32-bit, mereka memutuskan untuk memiliki int terus menjadi 4 byte dan mengharuskan Anda untuk memilih menggunakan tipe 8 byte dengan menentukan 'panjang'. panjang sebenarnya adalah ukuran kata asli pada x86-64. Salah satu cara untuk melihat ini adalah bahwa biasanya kompiler akan memberi pad struct Anda untuk membuat mereka selaras kata (meskipun mungkin ada arsitektur di mana ukuran kata dan keselarasan tidak terkait), jadi jika Anda membuat struct dengan int (32-bit) di dalamnya, dan panggil sizeof () di atasnya, jika Anda kembali 8 Anda tahu itu padding ke ukuran kata 64-bit.
Joseph Garvin
@SangeethSaravanaraj: Perhatikan bahwa secara teoritis ukuran kata asli CPU dan apa yang ditentukan kompiler adalah 'int' dapat berbeda, hanya saja konvensi untuk 'int' menjadi ukuran kata asli sebelum x86-64 muncul, di mana itu lama untuk memudahkan compat mundur.
Joseph Garvin
Terima kasih untuk penjelasannya! :)
Sangeeth Saravanaraj
7

Ukuran pointer pada dasarnya tergantung pada arsitektur sistem di mana ia diterapkan. Misalnya ukuran pointer dalam 32 bit adalah 4 byte (32 bit) dan 8 byte (64 bit) dalam mesin 64 bit. Jenis bit dalam sebuah mesin hanyalah alamat memori, yang dapat dimilikinya. Mesin 32 bit dapat memiliki 2^32ruang alamat dan mesin 64 bit dapat memiliki 2^64ruang alamat upto . Jadi pointer (variabel yang menunjuk ke lokasi memori) harus dapat menunjuk ke salah satu alamat memori ( 2^32 for 32 bit and 2^64 for 64 bit) yang dipegang mesin.

Karena alasan ini kita melihat ukuran pointer menjadi 4 byte dalam mesin 32 bit dan 8 byte dalam mesin 64 bit.

Rndp13
sumber
6

Selain perbedaan 16/32/64 bit bahkan hal-hal aneh dapat terjadi.

Ada mesin di mana sizeof (int *) akan menjadi satu nilai, mungkin 4 tetapi di mana sizeof (char *) lebih besar. Mesin yang secara alami menangani kata-kata alih-alih bytes harus "menambah" karakter pointer untuk menentukan bagian kata yang Anda inginkan untuk mengimplementasikan standar C / C ++ dengan benar.

Ini sekarang sangat tidak biasa karena perancang perangkat keras telah mempelajari nilai addressability byte.

Darron
sumber
4
Kompiler C untuk mesin vektor Cray, seperti T90, melakukan hal serupa. Alamat perangkat keras adalah 8 byte, dan arahkan ke kata 8-byte. void*dan char*ditangani dalam perangkat lunak, dan ditambah dengan 3-bit offset dalam kata - tetapi karena sebenarnya tidak ada ruang alamat 64-bit, offset disimpan dalam 3 bit orde tinggi dari 64-bit kata. Jadi char*dan int*ukurannya sama, tetapi memiliki representasi internal yang berbeda - dan kode yang mengasumsikan bahwa pointer "benar-benar" hanya bilangan bulat yang dapat gagal total.
Keith Thompson
5

8 bit dan 16 bit pointer digunakan di sebagian besar mikrokontroler low profile. Itu berarti setiap mesin cuci, mikro, lemari es, TV lama, dan bahkan mobil.

Bisa dibilang ini tidak ada hubungannya dengan pemrograman dunia nyata. Tapi di sini adalah satu contoh dunia nyata: Arduino dengan ram 1-2-4k (tergantung pada chip) dengan pointer 2 byte.

Baru-baru ini, murah, dapat diakses untuk semua orang dan layak untuk dikodekan.

Kobor42
sumber
4

Selain apa yang orang katakan tentang sistem 64-bit (atau apa pun), ada jenis pointer lain selain pointer-to-objek.

Sebuah pointer-to-member mungkin hampir semua ukuran, tergantung bagaimana mereka diimplementasikan oleh kompiler Anda: mereka bahkan belum tentu semua ukuran yang sama. Cobalah penunjuk-ke-anggota dari kelas POD, dan kemudian penunjuk-ke-anggota yang diwarisi dari salah satu kelas dasar dari sebuah kelas dengan banyak basis. Apanya yang seru.

Steve Jessop
sumber
3

Dari apa yang saya ingat, ini didasarkan pada ukuran alamat memori. Jadi pada sistem dengan skema alamat 32-bit, sizeof akan mengembalikan 4, karena itu 4 byte.

Will Mc
sumber
4
Tidak ada persyaratan seperti itu. Bahkan tidak ada persyaratan bahwa sizeof (unsigned int) == sizeof (signed int). Ukuran pointer ke int akan selalu, menurut definisi, sizeof (int *), ke char sizeof (char *) dll. Mengandalkan asumsi lain adalah ide yang buruk untuk portabilitas.
Mihai Limbășan
Ah, saya mengerti sekarang. Terimakasih atas infonya.
Will Mc
1
Masih dapat mengembalikan 2, jika CHAR_BIT adalah 16. sizeof () dihitung dalam jumlah karakter, bukan oktet.
MSalters
5
@Mihai: Di ​​C ++ sizeof (unsigned int) == sizeof (signed int), persyaratan ini ditemukan di 3.9.1 / 3. "Untuk masing-masing standar integer ditandatangani jenis, terdapat standar tipe unsigned integer yang sesuai (tetapi berbeda): unsigned char, unsigned short int, unsigned int, unsigned long int, dan unsigned long long int, yang masing-masing menempati jumlah yang sama penyimpanan dan memiliki persyaratan keselarasan sama dengan yang sesuai yang ditandatangani bilangan bulat jenis "
Ben Voigt
3

Secara umum, sizeof (hampir semuanya) akan berubah ketika Anda mengkompilasi pada platform yang berbeda. Pada platform 32 bit, pointer selalu berukuran sama. Pada platform lain (64 bit menjadi contoh nyata) ini dapat berubah.

Sean Reilly
sumber
3

Tidak, ukuran pointer dapat bervariasi tergantung pada arsitekturnya. Ada banyak pengecualian.

Hakim Maygarden
sumber
3

Ukuran pointer dan int adalah 2 byte dalam kompiler Turbo C pada mesin windows 32 bit.

Jadi ukuran pointer spesifik untuk kompiler. Tetapi umumnya sebagian besar kompiler diimplementasikan untuk mendukung variabel pointer 4 byte dalam 32 bit dan variabel pointer 8 byte dalam mesin 64 bit).

Jadi ukuran pointer tidak sama di semua mesin.

finalsemester.co.in
sumber
2

Alasan ukuran pointer Anda adalah 4 byte karena Anda mengkompilasi arsitektur 32-bit. Seperti yang FryGuy tunjukkan, pada arsitektur 64-bit Anda akan melihat 8.

Will Bickford
sumber
2

Di Win64 (Cygwin GCC 5.4) , mari kita lihat contoh di bawah ini:

Pertama, uji coba struct berikut:

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

struct test_struc{
    char a, b;
};

Kode tes di bawah ini:

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;    

Outputnya di bawah ini:

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

Anda dapat melihat bahwa dalam 64-bit, sizeof(pointer)adalah 8.

Jayhello
sumber
1

Pointer hanyalah sebuah wadah untuk sebuah alamat. Pada mesin 32 bit, rentang alamat Anda adalah 32 bit, jadi sebuah pointer akan selalu 4 byte. Pada mesin 64 bit jika Anda memiliki kisaran alamat 64 bit, sebuah pointer akan menjadi 8 byte.

Ed S.
sumber
1
Pada mesin 32-bit dengan byte 32-bit, sizeof (char *) bisa 1.
Robert Gamble
"... dengan 32-bit byte". Saya tidak tahu hal-hal seperti itu ada ... suka itu.
Ed S.
1
Pada bebek 32 bit, sizeof (char *) mengembalikan PI
Adriano Varoli Piazza
0

Hanya untuk kelengkapan dan minat historis, di dunia 64bit ada konvensi platform yang berbeda pada ukuran tipe lama dan panjang, bernama LLP64 dan LP64, terutama antara sistem tipe Unix dan Windows. Standar lama bernama ILP64 juga membuat lebar int = 64-bit.

Microsoft mempertahankan LLP64 di mana longlong = 64 bit lebar, tetapi lama tetap di 32, untuk porting lebih mudah.

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

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

Hernán
sumber