Правильный порядок включения как ‹cstdio›, так и ‹stdio.h›?

Мне нужно использовать системные функции, например. ftello() (определено в stdio.h согласно стандарту POSIX). Мне также нужно использовать стандартные функции С++, например. std::sprintf() (определено в cstdio согласно стандарту ISO C++).

Насколько мне известно, включение только <cstdio> не гарантирует определение нестандартных материалов C++, поэтому я думаю, что мне нужно включить оба. Я давно читал, что (например) с gcc могут быть проблемы с порядком включаемых файлов.

Итак, каков правильный порядок включения <cstdio> и <stdio.h>? Я ищу максимально кроссплатформенное решение (по крайней мере, для gcc, suncc, intel C++/linux и mingw).


person Alex    schedule 21.06.2009    source источник


Ответы (6)


Для системных заголовочных файлов порядок включения, как правило, не должен быть источником ошибок.

Для других файлов заголовков посмотрите на похожий вопрос здесь, в SO.

person Kosi2801    schedule 21.06.2009
comment
Спасибо за ответ. Я думаю, что нашел аналогичную проблему здесь: gcc.gnu.org/ml /libstdc++/2003-01/msg00210.html Я наткнулся на него некоторое время назад, но не помню подробностей. Заголовки определенно прошли через систему. Хотя это проблема системы/компилятора, я спрашивал, может быть, кто-то знает проверенный метод борьбы с такими вещами. - person Alex; 21.06.2009

Я не знаю ни одного истинного правила, однако, вообще говоря, я включаю системные библиотеки более низкого уровня перед библиотеками более высокого уровня.

Таким образом, в этом случае stdio.h является заголовком C и (в моем воображении) ближе к машине, а <cstdio> — это более высокий уровень, стандартная библиотека C++, которую я считаю более абстрактной.

Я сам склонен включать stdio.h перед cstdio, но я не знаю точной аргументации в поддержку этого обоснования.

person John Weldon    schedule 22.06.2009

ОК, после еще нескольких исследований я, наконец, пришел к выводу, что правильно включать заголовок C++ сначала, а затем заголовок C. Например, рассмотрим следующий заголовок C++0x (из gcc):

/usr/include/С++/4.3/tr1_impl/cstdint:


// ...
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
#include_next <stdint.h>
// ...

Он определяет два макроса C99 и только затем включает заголовок C99 stdint.h. Причина в том, что в C99 некоторые функции stdint.h являются необязательными и доступны только в том случае, если эти макросы определены. Однако в C++0x все функции stdint.h являются обязательными. Теперь, если я сначала включу C99 stdint.h, а затем cstdint, я не получу обязательные функции C++0x из-за защиты заголовков в stdint.h. Можно было бы возразить, что это вина производителя компилятора, но это было бы неверно. stdint.h — системный заголовок (в данном случае из glibc), который является заголовком C99 и ничего не знает о C++0x (в конце концов, это может быть старая система) или gcc. На самом деле компилятор не может исправить все системные заголовки (в данном случае всегда включать эти функции в режиме C++), но он должен обеспечить поддержку C++0x в этих системах, поэтому вместо этого поставщик использует этот обходной путь.

person Alex    schedule 18.07.2009

Насколько я могу судить, ftello() и sprintf() включены в stdio.h.

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

По этой причине зависимости включаемых файлов должны быть включены в включаемый файл, а не полагаться на «пользователя», чтобы обеспечить их правильное включение.

person Sev    schedule 21.06.2009
comment
Да, ftello() и sprintf() взяты из stdio.h, но я говорю о std::sprintf(), который может совпадать или не совпадать с sprintf(). На самом деле это, вероятно, не так, потому что sprintf() обычно является макросом, определяемым компилятором, а std::sprintf() гарантированно является функцией (адрес которой вы можете взять). Итак, мне нужно использовать ftello() из stdio.h и std::sprintf() из cstdio. Оба из стандартных включаемых файлов, но, поскольку эти два файла имеют особые отношения, я не знаю, какой правильный порядок надежно работает в различных комбинациях компилятор/ОС. - person Alex; 21.06.2009

Вы беспокоитесь без уважительной причины. Содержимое <cstdio> является «как бы включением» содержимого <stdio.h> (17.4.1.2 Заголовки/4). Однако объявления и определения (но не макросы) находятся в пространстве имен std.

Поэтому вам может понадобиться написать std::ftello(). Для улучшения портативности добавьте using std::ftello;, и вам не нужно беспокоиться об этом.

person MSalters    schedule 22.06.2009
comment
ftello() не входит в стандарт C++, и нет ftello() в пространстве имен std (по крайней мере, в gcc libstdc++). Спасибо, в любом случае! - person Alex; 23.06.2009
comment
Это именно моя точка зрения. Стандарт C++ не определяет, что именно находится в stdio.h. Он просто говорит, что cstdio содержит все, что находится в stdio.h, но в пространстве имен std. Если libstdc++ помещает ftello в stdio.h, но не в cstdio, это нарушает 17.4.1.2. - person MSalters; 24.06.2009

Я помещаю наиболее конкретные вещи вверху, а наименее специфичные — внизу. Например, для исходного файла это будет выглядеть так:

  1. Предварительно скомпилированный заголовок, если он есть
  2. Заголовок для этого исходного файла
  3. Проект включает
  4. Наиболее специфичные библиотеки, например, библиотеки в этом проекте или библиотеки компании.
  5. Наименее специфичные библиотеки, такие как «системные» библиотеки, такие как boost или SDL.
  6. Стандартный С++
  7. Стандарт С
  8. Заголовки операционной системы

Мое оправдание заключается в том, что более конкретные заголовки часто включают в себя более общие заголовки и хотят изменить их с помощью макросов. Если они уже включены, включите средства защиты, иначе значения макросов по умолчанию будут искажать поведение системных библиотек.

Другое оправдание заключается в том, что такой порядок не позволяет вам «скрывать» зависимости от других заголовков, то есть эти заголовки не будут автономными при включении из других исходных файлов, поскольку перед ними всегда были включены системные библиотеки.

person Matt Joiner    schedule 22.10.2009
comment
Это мой порядок включения тоже. :) За исключением того, что по какой-то причине я перемещаю 5 вниз после 8. - person Lightness Races in Orbit; 29.09.2011