Co oznacza && w void * p = && abc;

102

Natrafiłem na fragment kodu void *p = &&abc;. Jakie ma to znaczenie &&? Wiem o odwołaniach do wartości r, ale myślę, że &&w tym kontekście jest inaczej. Co to &&oznacza void *p = &&abc;?

Brent Arias
źródło
14
Gdzie to widziałeś?
user541686
3
Chciałbym też wiedzieć, gdzie to widzieliście.
Flavius

Odpowiedzi:

154

&&to rozszerzenie gcc służące do pobierania adresu etykiety zdefiniowanej w bieżącej funkcji.

void *p = &&abc jest nielegalne w standardowym C99 i C ++.

To kompiluje się z g ++.

Prasoon Saurav
źródło
42
Teraz wyobraź sobie, jak lepsi byliby wszyscy programiści, gdyby gcc miał domyślnie opcję -pedantic. Wtedy ludzie nauczyliby się C zamiast nieistotnych informacji o gnusie.
Lundin
4
Co za włamanie. Jeśli wymyślą nową składnię wskaźników etykiet, powinni również wymyślić dla niej nowy typ zamiast używać void*.
Mark Ransom
1
@Prasoon Saurav: Ktokolwiek przegłosował, prawdopodobnie nie pochwala tej funkcji i wyrzuca ją na ciebie.
Chuck
@Lundin: To samo można powiedzieć o większości kompilatorów. __forceinline? __declspec(naked)? Jednym z moich ulubionych MSVCism jest:, template<typename T> class X { friend T; }który jest nieprawidłowy w C ++ 03.
Sebastian Mach,
Drugie łącze nie działa.
Cœur
96

Jak się tego dowiedzieć

To adres etykiety i jest to funkcja specyficzna dla GCC .

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

Mogłeś się tego dowiedzieć, testując:

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

W takim przypadku GCC mówi:

błąd: etykieta „a” używana, ale nie zdefiniowana

Pod maską - montaż

Musisz znać asemblera, aby naprawdę to zrozumieć, ale spróbuję ci wyjaśnić, co oznacza adres etykiety.

Po załadowaniu przez system operacyjny pliku .exe z dysku, składnik systemu operacyjnego zwany „programem ładującym” (system Windows ma „moduł ładujący PE”, linux ma „moduł ładujący ELF” lub może nawet inne, jeśli są one skompilowane w jądro), dokonuje „wirtualizacji” tego programu, zamieniając go w proces.

Ten proces uważa, że ​​jest jedynym w pamięci RAM i ma dostęp do całej pamięci RAM (to znaczy 0x00000000-0xFFFFFFFF na komputerze 32-bitowym).

(powyższe to tylko krótki przegląd tego, co się dzieje, naprawdę musisz nauczyć się montażu, aby w pełni to zrozumieć, więc bądź ze mną)

Otóż ​​etykieta w kodzie źródłowym jest w zasadzie adresem. „goto label”; nie robi nic poza skokiem do tego adresu (pomyśl o wskaźniku instrukcji w asemblerze). Ta etykieta przechowuje ten adres RAM i w ten sposób możesz znaleźć ten adres.

Po nauczeniu się ASM zdasz sobie sprawę, że ten adres wskazuje na instrukcję w .textsekcji pliku wykonywalnego. .textSekcja jest ten, który posiada (binarnej) kod programu, który ma być wykonany.

Możesz to sprawdzić za pomocą:

objdump -x a.out

Praktyczny przykład

Jak opisano w GCC , możesz użyć tego do zainicjowania tablicy skoków. Niektóre generatory skanerów, takie jak re2c (patrz -gparametr), używają tego do generowania bardziej kompaktowych skanerów. Może jest nawet generator parsera wykorzystujący tę samą technikę.

Flavius
źródło
4
Skompiluj z -std = c99 -pedantic.
Lundin
2
Bardzo ważne jest, aby wspomnieć, że jest to rozszerzenie GCC, a nie podstawowa część języka
jalf
1
To całkiem imponujące Flavius.
Octavian A. Damiean
1
Podoba mi się ten rodzaj odpowiedzi, więcej ludzi trzeba uczyć, jak znaleźć odpowiedzi, a nie tylko ich mówić.
Letseatlunch
1
Dzięki za szczegółowe wyjaśnienie. Docenił analizę związaną z montażem.
CᴴᴀZ