Правильный порядок включения <cstdio>и <stdio.h>? - PullRequest
3 голосов
/ 21 июня 2009

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

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

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

Ответы [ 6 ]

2 голосов
/ 18 июля 2009

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

/ USR / включать / C ++ / 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 в этих системах, поэтому поставщик использует этот обходной путь вместо этого.

2 голосов
/ 22 июня 2009

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

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

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

2 голосов
/ 21 июня 2009

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

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

0 голосов
/ 22 октября 2009

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

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

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

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

0 голосов
/ 22 июня 2009

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

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

0 голосов
/ 21 июня 2009

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

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

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

...