Apa yang dimaksud && dalam void * p = && abc;

102

Saya menemukan sepotong kode void *p = &&abc;. Apa pentingnya di &&sini? Saya tahu tentang referensi rvalue tetapi menurut saya yang &&digunakan dalam konteks ini berbeda. Apa yang &&menunjukkan dalam void *p = &&abc;?

Brent Arias
sumber
14
dimana anda melihat ini?
pengguna541686
3
Saya juga ingin tahu di mana Anda pernah melihat ini.
Flavius

Jawaban:

154

&&adalah ekstensi gcc untuk mendapatkan alamat label yang ditentukan dalam fungsi saat ini.

void *p = &&abc ilegal dalam standar C99 dan C ++.

Ini dikompilasi dengan g ++.

Prasoon Saurav
sumber
42
Sekarang bayangkan bagaimana semua orang akan menjadi programmer yang lebih baik jika gcc memiliki -pedantic secara default. Kemudian orang akan mempelajari C, bukan informasi yang tidak relevan tentang gnus.
Lundin
4
Benar-benar hack. Jika mereka menemukan sintaks baru untuk penunjuk label, mereka harus menemukan tipe baru untuk itu juga daripada menggunakan void*.
Mark Ransom
1
@Prasoon Saurav: Siapa pun yang memberikan suara negatif mungkin tidak menyetujui fitur tersebut dan menimpanya kepada Anda.
Chuck
@ Lundin: Hal yang sama dapat dikatakan pada kebanyakan kompiler. __forceinline? __declspec(naked)? Salah satu MSVCisms favorit saya adalah:, template<typename T> class X { friend T; }yang merupakan C ++ 03 yang tidak valid.
Sebastian Mach
Tautan kedua sudah mati.
Cœur
96

Bagaimana cara menemukannya

Itulah alamat label dan merupakan fitur khusus GCC .

int main(void) {
    void* startp;
s:
    startp = &&s;
    printf("the assignment above starts at address %p\n", startp);
    return 0;
}

Anda bisa mengetahuinya sendiri dengan menguji:

int main(void) {
    void* startp;
    int a;
    startp = &&a;
    printf("startp=%p\n", startp);
    return 0;
}

Dalam hal ini GCC mengatakan:

kesalahan: label 'a' digunakan tetapi tidak ditentukan

Di bawah kap - perakitan

Anda perlu mengetahui assembler untuk benar-benar memahami ini, tetapi saya akan mencoba menjelaskan kepada Anda apa arti alamat sebuah label.

Setelah OS memuat file .exe dari disk, komponen sistem operasi disebut "the loader" (windows memiliki "PE Loader", linux memiliki "ELF loader" atau bahkan yang lain, jika dikompilasi di kernel), ia melakukan "virtualisasi" dari program itu, mengubahnya menjadi sebuah proses.

Proses ini menganggapnya sebagai satu-satunya di RAM dan memiliki akses ke seluruh RAM (yaitu, 0x00000000-0xFFFFFFFF pada mesin 32-bit).

(di atas hanyalah ringkasan singkat tentang apa yang terjadi, Anda benar-benar perlu belajar berkumpul untuk memahaminya sepenuhnya, jadi bersabarlah)

Sekarang, label dalam kode sumber pada dasarnya adalah sebuah alamat. "goto label;" tidak melakukan apa pun selain melompat ke alamat itu (pikirkan tentang penunjuk instruksi di assembly). Label ini menyimpan alamat RAM ini, dan begitulah cara Anda mengetahui alamat itu.

Setelah Anda mempelajari ASM, Anda akan menyadari bahwa alamat tersebut menunjuk ke sebuah instruksi di dalam .textbagian yang dapat dieksekusi. The .textBagian adalah salah satu yang memegang program yang ini (biner) kode yang akan dieksekusi.

Anda dapat memeriksanya dengan:

objdump -x a.out

Contoh praktis

Seperti yang dijelaskan di GCC , Anda dapat menggunakan ini untuk menginisialisasi tabel lompat. Beberapa generator pemindai seperti re2c (lihat -gparameter) menggunakannya untuk menghasilkan pemindai yang lebih ringkas. Mungkin bahkan ada generator parser yang menggunakan teknik yang sama.

Flavius
sumber
4
Kompilasi dengan -std = c99 -pedantic.
Lundin
2
Cukup penting untuk menyebutkan bahwa ini adalah ekstensi GCC, dan bukan bagian inti dari bahasa
jalf
1
Itu Flavius ​​yang cukup mengesankan.
Oktavianus A. Damiean
1
Saya suka jawaban seperti ini, lebih banyak orang perlu diajari cara menemukan jawaban daripada hanya diberi tahu.
Letseatlunch
1
Terima kasih atas penjelasannya yang mendalam. Menghargai analisis terkait Majelis.
CᴴᴀZ