2015-11-16 4 views
-1

Я намерен предоставить простые обертки API операционной системы, которые генерируют исключения при возникновении ошибок. Эти обертки просты и все они определены как встроенные функции в файле заголовка. Поскольку системный API должен быть большим, файл заголовка также должен быть огромным, содержащим большое количество мелких встроенных функций. Проблема состоит в том, что если совместно используемая библиотека (.so) скомпилирована с включенным файлом заголовка, все эти крошечные обертки будут скомпилированы в результирующий двоичный файл, что приведет к большому двоичному файлу, даже если на самом деле будет только небольшая часть оберток используемый? Что относительно случая с исполняемыми файлами, будет ли это иначе? Если это так, разделение оберток на несколько файлов заголовков будет единственным решением? Или я должен сделать внутреннюю привязку оберток, указав static?Встроенная функция компиляции

Вот что я думаю. Обертки могут быть использованы в ODR (например, для его адреса). На платформах Linux функции с внешней связью экспортируются по умолчанию (т. Е. Связаны с другими двоичными модулями). Поэтому, я думаю, может быть необходимым, чтобы компоновщик фактически генерировал для них общие определения. См. Пункт 3 маркировки) в Описание раздел here.

Простой пример упаковки CloseHandle() в Windows API:

inline void close_handle(HANDLE handle) { 
    if (!CloseHandle(handle)) { 
    throw std::system_error(GetLastError(), std::system_category(), "CloseHandle"); 
    } 
} 
+0

Я чувствую, что ваш вопрос слишком широк (вы не показываете какой-либо код), неясно, и вы слишком много заботитесь о неявных деталях (вы не сказали, что), что реализация на практике справляется достаточно хорошо. Сначала сначала создайте часть своей библиотеки, а затем задайте более целенаправленные вопросы с помощью некоторого фактического исходного кода. Конкретнее: какая ОС, какой компилятор, какие флаги компиляции, какой исходный код? –

+0

@BasileStarynkevitch Возможно, вы правы. Но то, что я хочу, - это (почти) прототипное решение на уровне исходного кода. Таким образом, параметры опций ОС, компилятора и компилятора не должны иметь значения. Я добавлю простой примерный код. – Lingxi

+0

Параметры компилятора * имеют значение *, поскольку некоторые компиляторы ('g ++' вероятно) не будут встроены в функции, если вы не попросите их оптимизировать. –

ответ

2

А (сравнительно небольшой) функция, объявленная static inline (или часто, только inline, или даже функция член определяется внутри некоторые class или struct) выиграл 't (на практике) появляются в коде, если он не используется (см. this), и, вероятно, будет встроен повсюду. Конечно, вам нужно включить оптимизацию в вашей команде компиляции. Итак, если вы используете GCC, скомпилируйте с помощью g++ -Wall -O2 (и вы можете добавить -fverbose-asm -S и заглянуть в сгенерированный код ассемблера, чтобы проверить).

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

Кстати, это может выглядеть вы изобретать рамки, аналогичную POCO или к Qt. Вы решили использовать их вместо этого?

Кроме того, недавние C++ 11 (и C++, 14) реализации уже оберточной значительную часть API ОС (в частности, стандарт C++ IO library и С ++ thread support library и совсем недавно C++ 14 TS), часто уже используя исключения, поэтому лучше использовать их и использовать недавний C++-компилятор (для GCC, это означает GCC 5.2 в ноябре 2015 года).

(Другими словами, код ваша вещь для C++ 11, по крайней мере, не C++ 98)

В Linux с GCC (или Clang/LLVM), если сделать библиотеку, вы можете быть заинтересованы в link-time-optimization (компиляция & link библиотека с g++ -O2 -flto), precompiled headers, visibility функция attributes.

Что касается программных библиотек в Linux, читайте Program Library HowTo.Для общие библиотеки, читайте статью Дреппера: How to Write Shared Libraries и this ответ.

На практике встроенная функция в некоторой библиотеке часто не выделяется в библиотеке, а в прикладной программе, вызывающей ее. Так что, если ваша общая библиотека Foo определяет в общественном заголовке <foo.h>

inline int maxsq(int a, int b) { 
    // you could add some conditional throw here... 
    if (std::abs(a) < std::abs(b)) return b*b; 
    else return a*a; 
} 

то объектный код maxsqвероятно не будет появляться внутри libfoo.so, но только в вашей программе (которая #include <foo.h> в исходном коде), если это программе необходимо указать maxsq, например сохраняет адрес maxsq где-нибудь (или если вы не запрашивали достаточную оптимизацию).

Помните, что inlining является всегда оптимизация, и некоторые компиляторы могут избежать этого (даже по соображениям хорошей производительности). На практике доверяет вашему компилятору (на самом деле ваша реализация на C++ также включает компоновщик, который может «собирать мусор» sections).

+1

[см. Здесь] (http://stackoverflow.com/questions/10876930/should-one-never-use-static-inline-function) для обсуждения 'static inline' в C++ –

+0

Надеюсь найти портативный источник -код-уровневое решение, которое работает без использования возможностей компилятора. Кроме того, мне нужен проверенный системный API, а не целая структура. Таким образом, POCO или Qt не соответствуют моим потребностям. Они оба очень приятные, конечно :) – Lingxi

+0

Вам не нужны опции компилятора twiddling. Но IMHO, GCC бесполезен для * производственного кода * без '-Wall' (для получения большинства предупреждений) и без' -O2' для получения оптимизаций, без которых производительность двоичной программы была бы плохой. –

Смежные вопросы