Що означає && void * p = && abc;


102

Я натрапив на фрагмент коду void *p = &&abc;. Яке значення &&тут? Я знаю про посилання rvalue, але я думаю, що &&використання в цьому контексті відрізняється. Що &&вказується на void *p = &&abc;?


14
Де ти це бачив?
користувач541686

3
Я також хотів би знати, де ви це бачили.
Флавій

Відповіді:


154

&&є розширенням gcc для отримання адреси мітки, визначеної у поточній функції.

void *p = &&abc є незаконним у стандарті C99 та C ++.

Це компілюється з g ++.


42
А тепер уявіть, як краще всі програмісти, якби gcc мав -педантичний за замовчуванням. Тоді люди дізнавалися б С замість невідповідної інформації про gnus.
Лундін

4
Який хак. Якщо вони вигадують новий синтаксис для покажчиків міток, вони також повинні винайти новий тип для нього, а не використовувати void*.
Марк Рансом

1
@Prasoon Saurav: Кожен, хто звернувся з пропозицією, мабуть, не схвалює цю функцію і знімає її на вас.
Чак

@Lundin: Те саме можна сказати і для більшості компіляторів. __forceinline? __declspec(naked)? Один з моїх улюблених MSVCisms:: template<typename T> class X { friend T; }, що недійсний C ++ 03.
Себастьян Мах

Друга ланка мертва.
Cœur

96

Як це дізнатися

Це адреса етикетки і це особливість, характерна для GCC .

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

Ви могли самі це зрозуміти, тестуючи:

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

У такому випадку GCC говорить:

помилка: мітка 'a' використовується, але не визначена

Під кришкою - збірка

Вам потрібно знати асемблера, щоб реально зрозуміти це, але я спробую пояснити вам, що означає адреса етикетки.

Після завантаження ОС на файл .exe з диска, компонент операційної системи, який називається "навантажувач" (у Windows є "PE Loader", у Linux є "ELF loader" або, можливо, навіть інші), якщо вони складені в ядро), воно робить "віртуалізацію" цієї програми, перетворюючи її на процес.

Цей процес вважає, що він є єдиним в оперативній пам'яті, і він має доступ до всієї ОЗУ (тобто 0x00000000-0xFFFFFFFF на 32-бітній машині).

(вище - лише короткий перегляд того, що відбувається, вам дійсно потрібно навчитися збірці, щоб зрозуміти це повністю, тому поводьтеся зі мною)

Тепер мітка у вихідному коді - це в основному адреса. "goto label;" не робить нічого іншого, як стрибок на цю адресу (подумайте про вказівник інструкцій щодо складання). Ця мітка зберігає цю адресу оперативної пам’яті, і саме так ви можете дізнатися її.

Після того як ви дізналися ASM, ви зрозумієте, що ця адреса вказує на інструкцію в .textрозділі виконуваного файлу. .textРозділ є той , який має код , який ви програма (двійковий) для виконання.

Ви можете перевірити це за допомогою:

objdump -x a.out

Практичний приклад

Як описано в GCC , ви можете використовувати це для ініціалізації таблиці стрибків. Деякі генератори сканерів, такі як re2c (див. -gПараметр), використовують для створення більш компактних сканерів. Можливо, є навіть генератор парсера, який використовує ту саму техніку.


4
Компілюйте з -std = c99 -педантичним.
Лундін

2
Досить важливо зазначити, що це розширення GCC, а не основна частина мови
jalf

1
Це досить вражаючий Флавій.
Октавіан А. Дам’ян

1
Мені подобається така відповідь, більше людей потрібно вчити, як шукати відповіді, а не просто говорити.
Letseatlunch

1
Дякую за глибоке пояснення. Оцінив аналіз, пов'язаний з Асамблеєю.
CᴴᴀZ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.