Подтвердить что ты не робот

Должен ли я включать <xxxx.h> или <cxxxx> в программы на С++?

  • Что я должен включить в программы на С++, stdio.h или cstdio? и почему?
  • Почему два файла заголовка предоставляют одну и ту же функциональность?
  • Что говорит об этом стандарт?
  • Как мне включить другие такие заголовки, есть ли базовое правило, которому я должен следовать?
4b9b3361

Ответ 1

Рассмотрим следующие программы:

Пример 1:

#include<stdio.h>

int main()
{
    printf("Hello World");
    return 0;
}

Пример 2:

#include<cstdio>

int main()
{
    printf("Hello World");
    return 0;
}

Оба работают так, как ожидалось. Итак, какое использование более подходит? Ответ: Ничего! Удивлен? Читай дальше.

Стандартная библиотека С++ предоставляет все стандартные заголовки C для обеспечения совместимости, в то время как язык С++ также предоставляет все эквивалентные заголовки. Как соглашение,

  • Нет стандартных заголовков библиотек С++ (кроме них, для совместимости с C), есть расширения файлов и
  • Все С++-эквиваленты заголовков C начинаются с cxxxxx.

Стандарт С++ упоминает это в Приложении D (нормативный). Особенности совместимости:

Standard Citation

В § 2 упоминается важная отличительная точка. Это правило применяется к приведенным выше примерам:

  • Включение cstdio импортирует имена символов в пространстве имен std и возможно в глобальном пространстве имен.
  • Включение stdio.h импортирует имена символов в глобальном пространстве имен и возможно в пространстве имен std.

Давайте применим это правило к нашим образцовым кодам и оценим плюсы и минусы:

Пример 1: Это приводит ко всем символам из stdio.h в глобальном пространстве имен. Преимущество состоит в том, что вы можете использовать символы без какой-либо квалификации, так как они импортируются в глобальное пространство имен. Недостатком является то, что вы в конечном итоге загрязняете глобальное пространство имен многими именами символов, которые вы, вероятно, никогда не будете использовать. Это может привести к столкновению имен символов. В С++ всегда рассматривайте глобальное пространство имен как минное поле и избегайте его как можно больше.

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

Итак, каково правильное использование?

Правильное использование - использовать cstdio и полностью квалифицировать имена символов, а также приводить их в область с using declarations. Это гарантирует, что все используемые символы присутствуют в пространстве имен std, и мы не загрязняем глобальное пространство имен. Пример правильного использования:

Пример 3:

#include<cstdio>

using std::printf;

int main()
{
    printf("Hello World");
    return 0;
}

Обратите внимание, что директива using namespace std;, особенно в заголовке, не является хорошим вариантом, и вы всегда должны использовать объявления using.

Обратите внимание, что мы рассматриваем stdio.h vs. cstdio здесь только пример использования, на практике он применим к all заголовкам cxxxx и xxxx.h, за исключением нескольких, таких как <math.h> и <cmath>.

Ответ 2

Поскольку этот пост немного устарел, я хотел бы поделиться следующим:


Глядя на код:

Using X.h   // Compatible with C language standard
---------------
#include <X.h>

int main() {
    // Invoke X corresponding function
    return 0;
}

Using X    // Not compatible with C language standard
--------------
#include <X>

int main() {
    // Invoke X corresponding function
    return 0;
}

Они компилируются и выполняются нормально!


Какой из них лучше в С++?

Относительно С++ 11 и С++ 17 спецификации:

C.5.1 (раздел из документа С++ 17)
Модификации заголовков [diff.mods.to.headers]

  • Для совместимости со стандартной библиотекой C стандартная библиотека С++ предоставляет заголовки C, перечисленные в D.5, но их использование устарел на С++.

  • Нет заголовков С++ для заголовков C <stdatomic.h>, <stdnoreturn.h> и <threads.h>, а также не являются заголовками C часть С++.

  • Заголовки С++ <ccomplex> (D.4.1) и <ctgmath> (D.4.4), а также их соответствующие заголовки C <complex.h> и <tgmath.h>, не содержат любое содержимое из стандартной библиотеки C и вместо этого просто включите другие заголовки из стандартной библиотеки С++.


Г .5 стандартные заголовки библиотеки [des.c.headers]1. Для совместимости со стандартной библиотекой C стандартная библиотека С++ предоставляет заголовки C, показанные в таблице 141.

введите описание изображения здесь

Оба документа С++ 11 и С++ 17 заявляют, что использование <X.h> остается совместимым со стандартом C, хотя их использование рассматривается как устарел.


Относительно стандартное предложение С++ 20

Они анализируют "неопубликование" использование заголовков библиотеки C в С++ 20. <X.h> отображаются зеленым цветом. Отказ С++ 11 и С++ 17 на данный момент указан как "слабая рекомендация" и "настройка" для хранения " C стандартных заголовков библиотек (c.headers )":

"Основные заголовки библиотеки C - важная функция совместимости, и в ближайшее время они не собираются никуда". (из С++ 20 review документ)


Стандарт D.5 C
заголовки библиотек [des.c.headers]

Слабая рекомендация: В дополнение к вышесказанному, также удалите соответствующие C заголовки из стандарта С++, так как у нас нет соответствующие <stdatomic.h>, <stdnoreturn.h> или <threads.h>, заголовки. Как и выше, но со следующими настройками: 20.5.5.2.1 C стандартные заголовки библиотек [c.headers]

Для совместимости со стандартной библиотекой C стандарт С++ библиотека предоставляет заголовки C, показанные в таблице 141. Таблица 141 - C заголовки

 <assert.h>  <inttypes.h>   <signal.h>      <stdio.h>   <wchar.h>
 <complex.h> <iso646.h>     <stdalign.h>    <stdlib.h>  <wctype.h>
 <ctype.h>   <limits.h>     <stdarg.h>      <string.h>  
 <errno.h>   <locale.h>     <stdbool.h>     <tgmath.h>
 <fenv.h>    <math.h>       <stddef.h>      <time.h>
 <float.h>   <setjmp.h>     <stdint.h>      <uchar.h>

Заголовок <complex.h>ведет себя так, как будто он просто включает заголовок. Заголовок <tgmath.h> ведет себя так, как будто он просто включает заголовки <complex> и <cmath>.


Bjarne Stroustrup рекомендует максимизировать межоперативность между языки C и С++, уменьшают несовместимость столько, сколько возможное. Другие утверждают иначе, поскольку это усложняет ситуацию.

Итак, кажется, что <X.h> не никуда не годится. В конечном счете, вы можете использовать оба. Лично я бы принял решение о том, какой из них я бы использовал, чтобы ваш код был обратно совместим с кодом C или нет.