Pertanyaan Mengapa hasil dari ini tidak memberikan nilai?


Saya butuh saran dengan perilaku aneh ini - mari kita memiliki kode ini:

int ** p;

Ini mengkompilasi tanpa masalah:

p++;

Tapi ini:

((int**)p)++;

Memberi saya pesan kesalahan ini: “error: lvalue required as increment operand”.

Saya melakukan casting p untuk tipe yang sudah ada, tidak ada perubahan, jadi apa masalahnya? Ini adalah versi sederhana dari masalah yang saya temui, ketika saya mencoba untuk mengkompilasi yang lama  versi dari gdb. Jadi saya kira, ini berhasil dan sesuatu berubah. Tahu apa yang salah dengan contoh kedua?


5
2018-01-27 16:42


asal


Jawaban:


Versi lama dari gcc mendukung sesuatu yang disebut "lvalue cast" - jika Anda melemparkan sesuatu yang bernilai, hasilnya adalah nilai dan dapat diperlakukan seperti itu. Penggunaan utama untuk itu adalah memungkinkan Anda untuk menaikkan pointer dengan jumlah yang sesuai dengan ukuran yang berbeda:

int *p;
++(char *)p;  /* increment p by one byte, resulting in an unaligned pointer */

Ekstensi ini tidak lagi digunakan di sekitar gcc v3.0 dan dihapus di gcc v4.0

Untuk melakukan hal yang sama pada versi gcc yang lebih baru, Anda perlu melakukan penambahan dan penugasan (alih-alih penambahan) untuk mentransmisikan pointer ke jenis untuk penambahan dan kembali untuk penugasan:

p = (int *)((char *)p + 1);

Perhatikan bahwa mencoba untuk mengalihkan pointer setelah ini adalah perilaku yang tidak terdefinisi, jadi jangan berharap untuk melakukan sesuatu yang bermanfaat.


6
2018-01-27 16:59



Saat Anda mengetik ekspresi, hasil dari ekspresi tersebut adalah rvalue dan bukan nilai. Secara intuitif, sebuah typecast mengatakan "beri aku nilai bahwa ekspresi ini akan memiliki jika ada tipe lain, "jadi typecasting variabel ke jenisnya sendiri masih menghasilkan nilai dan bukan nilai. Akibatnya, itu tidak sah untuk menerapkan ++ operator untuk hasil dari typecast, sejak ++ membutuhkan lvalue dan Anda memberikan rvalue.

Yang mengatakan, pada prinsipnya mungkin untuk mendefinisikan ulang bahasa C sehingga casting nilai ke jenis sendiri menghasilkan nilai jika ekspresi asli adalah nilai, tetapi untuk kesederhanaan dan demi konsistensi saya kira desainer bahasa tidak melakukan ini.

Semoga ini membantu!


4
2018-01-27 16:45



Mengapa hasil dari ini tidak memberikan nilai?

Saya menarik perhatian Anda ke bagian 6.5.4 dari spesifikasi C99, baris 4, catatan kaki 86, yang menyatakan:

Pemeran tidak menghasilkan lvalue.

Anda memiliki pemain.

Hasilnya bukan nilai lv.

Itu ++ operator membutuhkan nilai lv.

Oleh karena itu program Anda merupakan kesalahan.


4
2018-01-27 19:13



Dalam bahasa C, semua konversi (termasuk cetakan eksplisit) selalu menghasilkan rujukan. Tidak ada pengecualian. Kenyataan bahwa Anda mentransmisikannya ke jenis yang sama tidak membuatnya dibebaskan dari aturan itu. (Sebenarnya, akan aneh untuk mengharapkannya membuat pengecualian yang tidak konsisten seperti itu.)

Bahkan, salah satu sifat dasar dari seluruh bahasa C adalah bahwa ia selalu mengubah nilai menjadi rujukan dalam ekspresi sesegera mungkin. Nilai dalam ekspresi C adalah seperti elemen ke-115 tabel Mendeleev: mereka biasanya menjalani kehidupan yang sangat singkat, cepat membusuk menjadi rujukan. Ini adalah perbedaan utama antara C dan C ++, dengan yang terakhir selalu berusaha untuk mempertahankan nilai dalam ekspresi selama mungkin (meskipun dalam C + + pemain khusus ini juga akan menghasilkan rvalue).


3
2018-01-27 16:59