Bagaimana inisialisasi nilai “int * ptr = int ()” tidak ilegal?

86

Kode berikut (diambil dari sini ):

int* ptr = int();

mengkompilasi dalam Visual C ++ dan menginisialisasi nilai penunjuk.

Bagaimana mungkin? Maksud saya int()menghasilkan sebuah objek bertipe intdan saya tidak dapat menetapkannya intke sebuah pointer.

Bagaimana kode di atas tidak ilegal?

gigi tajam
sumber
Bukan jawaban, tapi pertanyaan bagus! Saya belum pernah melihat hal seperti itu.
Josh
6
Karena primitif memiliki 'konstruktor' dalam C ++, int()menghasilkan nilai nilai yang dibangun int(yang menurut saya adalah hal yang ditentukan C ++ 03) dan nilai default intadalah 0. Ini setara denganint *ptr = 0;
wkl
7
@EmanuelEy: Tidak, setiap konstanta bilangan bulat bernilai nol dapat digunakan sebagai konstanta penunjuk nol, terlepas dari bagaimana sebenarnya penunjuk diimplementasikan.
Mike Seymour
1
@MooingDuck: Saya tidak mengatakan NULLbisa menjadi nilai bukan nol. Saya mengatakan itu bisa berupa konstanta integer bernilai nol (yang mencakup int()).
Mike Seymour
5
@DanielPryden Itu adalah penggunaan kata "objek" yang sebelumnya tidak saya sadari.
lembut

Jawaban:

110

int()adalah ekspresi konstanta dengan nilai 0, jadi ini cara yang valid untuk menghasilkan konstanta penunjuk nol. Pada akhirnya, itu hanya cara mengatakan yang sedikit berbedaint *ptr = NULL;

Jerry Coffin
sumber
3
+1, bit ekspresi konstan itu penting dan hilang dari 2 jawaban yang diberi suara positif teratas.
David Rodríguez - dribeas
apakah ini hilang dengan C ++ 0x?
Neil G
@NeilG: Ini tetap sama di C ++ 11, meskipun sekarang ada juga a nullptr, yang dapat Anda gunakan sebagai ganti 0atau NULLdalam kode baru.
Jerry Coffin
2
@Nils: Kejelasan kode dan menyatakan maksud Anda melalui kode. Tentu saja, dengan C ++ 11, sekarang Anda ingin menggunakan nullptr karena ia juga membuang manfaat pemeriksaan waktu kompilasi tambahan ke dalam campuran.
Jamin Gray
3
@ Nils karena cukup jelas 0dapat berarti konstanta penunjuk nol atau angka 0, sedangkan nullptrjelas merupakan konstanta penunjuk nol. Selain itu, seperti yang dikatakan Jamin, juga ada "pemeriksaan waktu kompilasi ekstra". Cobalah untuk berpikir sebelum mengetik.
Rute Miles
35

Karena int()hasil 0, yang dapat dipertukarkan dengan NULL. NULLsendiri didefinisikan sebagai 0, tidak seperti C NULLyang ada (void *) 0.

Perhatikan bahwa ini akan menjadi kesalahan:

int* ptr = int(5);

dan ini masih akan berhasil:

int* ptr = int(0);

0adalah nilai konstanta khusus dan karenanya dapat diperlakukan sebagai nilai penunjuk. Ekspresi konstan yang menghasilkan 0, seperti 1 - 1juga diperbolehkan sebagai konstanta penunjuk-nol.

Buyukliev Blagovest
sumber
1
Perhatikan juga bahwa C's NULL belum tentu (void *)0juga. Ini hanyalah implementasi yang didefinisikan "ekspresi konstan integer dengan nilai 0, atau ekspresi seperti itu dilemparkan ke tipe void *".
Jerry Coffin
@JerryCoffin Saya tidak pernah menggunakan kompilator C yang didefinisikan NULLsebagai (void*)0; itu selalu 0(atau mungkin 0L). (Tapi kemudian, pada saat C90 (void*)0dilegalkan di C, saya sudah menggunakan C ++.)
James Kanze
1
@JamesKanze: Di ubuntu 11.04 dan linux kami sendiri, libio.h berisi: #if !defined(__cplusplus) \n #define NULL ((void*)0) \n #else \n #define NULL (0)versi gcc saat ini di ubuntu adalah 4.5, di sistem kami adalah 4.0.
David Rodríguez - dribeas
5
" 0adalah literal khusus" - hanya karena ini adalah ekspresi konstan, dan memiliki nilai khusus 0. (1-1)sama istimewanya, juga konstanta penunjuk nol, dan begitu juga int(). Fakta 0literal sudah cukup tetapi tidak perlu kondisi untuk menjadi ekspresi konstan. Sesuatu seperti strlen(""), meskipun juga memiliki nilai khusus 0, bukanlah ekspresi konstan dan karenanya bukan konstanta penunjuk nol.
Steve Jessop
@SteveJessop: Saya setuju tentang koreksi, ini benar-benar tentang nilai konstan 0, bukan 0literal.
Blagovest Buyukliev
18

Ekspresi int()mengevaluasi ke bilangan bulat default-diinisialisasi konstan, yang merupakan nilai 0. Nilai itu khusus: digunakan untuk menginisialisasi pointer ke status NULL.

Mark Ransom
sumber
2
Ini kehilangan detail yang sangat penting yang ada dalam jawaban Jerry: tidak cukup bahwa ekspresi menghasilkan nilai 0, tetapi harus juga ekspresi konstan . Untuk contoh tandingan, dengan int f() { return 0; }, ekspresi f()menghasilkan nilai 0, tetapi tidak dapat digunakan untuk menginisialisasi penunjuk.
David Rodríguez - dribeas
@ DavidRodríguez-dribeas, saat saya terburu-buru untuk menyajikan jawaban dalam istilah yang paling sederhana, saya meninggalkan bagian itu. Saya harap itu bisa diterima sekarang.
Tandai Tebusan
13

Dari n3290 (C ++ 03 menggunakan teks serupa), 4.10 Konversi penunjuk [konv.ptr] paragraf 1 (penekanannya ada pada saya):

1 Konstanta penunjuk null adalah ekspresi konstanta integral (5.19) nilai prnilai tipe integer yang mengevaluasi ke nol atau prvalue tipe std :: nullptr_t. Konstanta penunjuk null dapat diubah menjadi jenis penunjuk; hasilnya adalah nilai penunjuk nol dari jenis itu dan dapat dibedakan dari setiap nilai penunjuk objek atau jenis penunjuk fungsi lainnya. Konversi seperti itu disebut konversi penunjuk nol. [...]

int()adalah ekspresi konstan integral dari tipe integer yang mengevaluasi ke nol (itu seteguk!), dan dengan demikian dapat digunakan untuk menginisialisasi tipe pointer. Seperti yang Anda lihat, 0itu bukan satu-satunya ekspresi integral yang dikurung khusus.

Luc Danton
sumber
4

Yah int bukanlah sebuah objek.

Saya percaya apa yang terjadi di sini adalah Anda memberi tahu int * untuk menunjuk ke beberapa alamat memori yang ditentukan oleh int ()

jadi jika int () membuat 0, int * akan menunjuk ke alamat memori 0

Megatron
sumber
1
int()pasti adalah sebuah objek.
Balapan Ringan di Orbit
@Tomalak: Sepertinya tidak. Ini adalah sementara dari tipe non-kelas, dan saya pikir saya benar mengatakan bahwa ini bukan objek sejauh menyangkut standar C ++. Ini agak aneh, meskipun, bagian tentang "objek sementara" dimulai dengan hati-hati hanya berbicara tentang temporer dari tipe kelas, tetapi kemudian berbicara tentang referensi yang mengikat, dan tentu saja Anda dapat mengikat referensi ke int(). Definisikan int i;, maka tidak ada pertanyaan, iadalah sebuah objek.
Steve Jessop
@ Steve: Saya hanya mengharapkan perdebatan tentang ini karena "objek" adalah wilayah penyimpanan di C ++, dan sementara tidak benar-benar memiliki penyimpanan, bukan? 1.8 / 1 tidak secara eksplisit mencantumkan temporer, tetapi rasanya seolah-olah ada niat untuk menyertakannya.
Balapan Ringan di Orbit
1
@Tomalak: ya memang, sementara tipe non-kelas tidak perlu penyimpanan kecuali Anda mengambil referensi. Tidak apa-apa, itu tidak terlalu penting. Pernyataan "baik int bukanlah objek" hanya benar karena intmerupakan tipe, bukan objek. Apakah int()menghasilkan suatu objek atau hanya nilai r tidak mempengaruhi apa pun yang dikatakan orang di tempat lain.
Steve Jessop
@ Steve: Itu tidak bisa dibantah :)
Lightness Races in Orbit