Что означает добавление переменной препроцессора перед объявлением функции? - PullRequest
0 голосов
/ 06 мая 2020

Я читаю Dear Im Gui API, и мне интересно, что значит добавить переменную препроцессора (здесь IMGUI_API ) перед функцией объявление вроде этого:

#ifndef IMGUI_API
#define IMGUI_API
#endif

...

namespace ImGui
{
    ...
    IMGUI_API float         GetWindowWidth();
    ...
};

Заранее спасибо!

1 Ответ

1 голос
/ 06 мая 2020

Как сказал Ганс Пассан - он не всегда будет пустым.

Одно из основных свойств общих объектов c Dynami (и DLL в Windows) заключается в том, что внутренние символы библиотеки не предоставляются пользователю. В G CC это делается путем определения видимости символа по умолчанию как «скрытый» в командной строке при построении библиотеки. Однако это имеет нежелательный эффект, заключающийся в том, что все символы, включая те, которые вы хотите, чтобы пользователи вызывали, становятся скрытыми, что делает вашу библиотеку практически бесполезной.

G CC позволяет вручную управлять видимостью - __attribute__((visibility("default"))). Это помечает функцию как имеющую видимость по умолчанию, то есть она будет предоставлена ​​DSO. Этот атрибут указывается перед объявлением функции.

Это создает новую проблему - пользователям вашей библиотеки не нужен / не нужен этот атрибут, указанный в ваших библиотечных функциях, когда они включают ваш файл заголовка. Когда ваш заголовок включен пользователем, эти определения следует удалить, оставив только объявление функции.

Есть два способа решить эту проблему - иметь две копии вашего заголовка или использовать препроцессор для изменения кода перед компиляцией. Большинство (почти все) библиотечных программистов выбирают последнее, так как синхронизировать две копии одного и того же файла очень сложно.

Способ, которым авторы Im Gui реализовали последний вариант, довольно элегантен, а не определяя свой маркер API в строке, например:

#ifdef IMGUI_API_BUILD
#define IMGUI_API __attribute__((visibility("default")))
#else
#define IMGUI_API 
#endif

Они определили его следующим образом:

#ifndef IMGUI_API
#define IMGUI_API 
#endif

Это имеет эффект определения символа в значение по умолчанию, если он имеет не было отменено.

Гениальность этого на самом деле заключается в процессе компиляции - указав определение IMGUI_API в командной строке, они могут изменить поведение кода, не подвергая элементы процесса сборки к миру.

Все, что им нужно сделать, это добавить -D IMGUI_API=__attribute((visibility("default"))) в командную строку компилятора, и файл заголовка волшебным образом помечает каждую функцию API как экспортируемую из общего объекта.

Фактически, они могут изменить определение на любое значение, которое они хотят, не раскрывая эту деталь в файле заголовка, используемом таким образом другими программистами. Информация об отладке, дополнительные параметры функций, указание информации о горячем / холодном пути ... все это можно указать в командной строке без необходимости помещать эту информацию в файл заголовка.

Изменить:

Просматривая их код сейчас, кажется, что они этого не осознали и создали очень мощное решение с разделяемой библиотекой для Linux, даже не желая этого. Несмотря на это, все вышеперечисленное остается в силе - другие библиотеки могут делать то же самое.

...