При использовании заголовков C в C ++ должны ли мы использовать функции из std :: или глобального пространства имен?

113

C в некоторой степени, не совсем так, является подмножеством C ++. Таким образом, мы можем использовать большинство функций / заголовков C в C ++, немного изменив имя ( stdio.hна cstdio, stdlib.hна cstdlib).

На самом деле мой вопрос носит семантический характер. В коде C ++ ( с использованием новейшей версии GCC компилятора), я могу позвонить printf("Hello world!");и std::printf("Hello world!");и она работает точно так же. И в ссылке, которую я использую, он также отображается как std::printf("Hello world!");.

Мой вопрос в том, что лучше использовать std::printf();в C ++? Есть разница?

DeiDei
источник
17
В случае, если однажды они потребуют, чтобы сброс Cсимволов библиотеки в глобальное пространство имен был незаконным, я предпочитаю использовать std::подходящие версии. (Плюс мне бы хотелось, чтобы они сделали это незаконным).
Галик
3
@Galik: Согласен. Это избавит от множества глупых вопросов о проблемах C с использованием компилятора C ++.
слишком честно для этого сайта
7
Не бывает «немножко беременной». Либо C является подмножеством, либо нет. На самом деле это не так . По этой причине заголовки C должны быть изменены для работы в C ++.
слишком честно для этого сайта
2
«почти все» - довольно бесполезная мера, когда мы говорим о наборе бесчисленного множества элементов. По тому же аргументу вы, вероятно, могли бы связать C и Java.
Даниэль Джур
9
@sasauke нет, это не подмножество. C и C ++ определенно разделяют подмножество, но сам C не является подмножеством C ++.
Парамагнитный круассан

Ответы:

106

Из стандарта С ++ 11 (выделено мной):

D.5 Заголовки стандартной библиотеки C [depr.c.headers]

  1. Для совместимости со стандартной библиотекой C ...
  2. Каждый заголовок C, каждый из которых имеет имя формы name.h , ведет себя так, как если бы каждое имя, помещенное в пространство имен стандартной библиотеки соответствующим заголовком cname, помещалось в область глобального пространства имен . Это не определено , являются ли эти имена первых объявлены или определены в пределах области видимости пространства имен (3.3.6) из пространства имен Std и затем вводят в глобальной области видимости пространства имен явными с использованием деклараций (7.3.3).
  3. Пример: заголовок, <cstdlib> несомненно, предоставляет свои объявления и определения в пространстве имен std . Он также может предоставлять эти имена в глобальном пространстве имен. Заголовок, <stdlib.h> несомненно, предоставляет те же объявления и определения в глобальном пространстве имен , как и в стандарте C. Он также может предоставлять эти имена в пространстве имен std.

Использование заголовков «name.h» не рекомендуется, они были определены как кандидаты на удаление из будущих версий.

Итак, я бы предложил включить заголовки «cname» и использовать объявления и определения из stdпространства имен.

Если вам по каким-то причинам необходимо использовать заголовки «name.h» (они устарели, см. Выше), я бы предложил использовать объявления и определения из глобального пространства имен.

Другими словами: предпочитаю

#include <cstdio>

int main() {
    std::printf("Hello world\n");
}

над

#include <stdio.h>

int main() {
    printf("Hello world\n");
}
Sergej
источник
1
N3242 не является стандартом C ++. N3337 черновик с наименьшими отличиями от C ++ 11.
MM
3
Также см. Статью Джонатана Уэйкли, почему <cstdlib> сложнее, чем вы можете подумать из блогов Red Hat. Он подробно описывает ряд проблем с точки зрения разработчика стандартной библиотеки C ++. Он также приводит историю, восходящую к C ++ 98.
jww 08
@sergej - Знаете ли вы, как C ++ 03 рассматривает эту тему? Или это удачно или нет, что произойдет?
jww 08
5
<name.h> может быть устаревшим, нет никаких шансов, что они будут удалены в ближайшее время. Наоборот, на самом деле. Есть предложение удалить устаревшую метку, см. Open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0619r0.html#3.5 . «Наконец, представляется очевидным , что заголовки C будут сохранены по существу навсегда, как жизненно важный слой совместимости с C и POSIX Это может быть стоит undeprecating заголовков, [..].»
Сьерда
82

<cmeow>всегда предоставляет ::std::purrи может или не может предоставить ::purr.

<meow.h>всегда предоставляет ::purrи может или не может предоставить ::std::purr.

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

TC
источник
7
STL в плохой маскировке?
nwp
@nwp нет. (15 символов)
TC
@TC К сожалению, пока я пробовал свой компилятор, ни и <cmeow>не <meow.h>выдает ни, ::std::purrни ::purrскорее ошибку препроцессора. Только <cstdio>и / или <stdio.h>предоставляет ::std::printfи / или ::printf. : P
LF
4
@LF Вам может понадобиться strcatпроизвести ::purr.
Lundin
8

Нет, ты в любом случае в порядке.

Оригинальное намерение состояло в том, что <___.h>заголовки были бы C версию , которые ставят все в глобальном пространстве имен, и <c___>заголовки будут быть C ++ - маньяки версия, что место все в stdпространстве имен.

Однако на практике версии C ++ также помещают все в глобальное пространство имен. И нет четкого консенсуса в отношении того, что использование std::версий «правильно».

В общем, используйте то, что вам больше нравится. Наиболее распространенным, вероятно, является использование функций стандартной библиотеки C в глобальном пространстве имен ( printfвместо std::printf), но нет особых причин считать одну «лучше» другой.

Jalf
источник
2
«И нет четкого консенсуса относительно того, что использование std :: versions - это« правильный поступок »». Да, абсолютно все согласны с тем, что это правильно.
Miles Rout
4
Как объективно определить, достигнут консенсус или нет?
Джереми Фриснер
9
@JeremyFriesner, вы публикуете об этом на SO и смотрите, не получите ли вы несогласные комментарии. :)
jalf
1
@JeremyFriesner: Стандарт не гарантирует, что версии заголовков C ++ помещают идентификаторы в глобальное пространство имен. Стандарт также не рекомендует версии заголовков C. Мне это кажется довольно консенсусным. ;-)
DevSolar
2
@DevSolar тогда поищи слово «консенсус» в словаре. Дело не в том, что говорится в стандарте, а в том, что говорят программисты на C ++ - и особенно, что они делают . Есть причина, по которой буквально каждая реализация стандартной библиотеки предоставляет заголовки C, а заголовки C ++ также помещают все в глобальное пространство имен. :)
jalf
3

Единственное отличие состоит в том, что std::printf(), добавив std::разрешение области видимости, вы обезопасите себя от того, что кто-то напишет функцию с тем же именем в будущем, что приведет к конфликту пространства имен. Оба использования приведут к точно таким же вызовам API ОС (вы можете проверить это в Linux, запустив strace your_program).

Я считаю очень маловероятным, что кто-то назовет такую ​​функцию таким, поскольку printf()это одна из наиболее часто используемых функций. Кроме того, в C ++ iostreams предпочтительнее вызовов cstdioтаких функций, как printf.

синтагма
источник
1
Напротив, я считаю это весьма вероятным: printfв C ++ он сильно сломан из-за отсутствия строгой типизации, замена его на лучшую версию вполне естественна.
Конрад Рудольф
1
@KonradRudolph Вы можете найти это так, если хотите, но вы ошибаетесь; он не предназначен для строгой типизации, и есть много проблем, которые не могут быть легко решены с помощью требуемой строгой типизации. Вот почему многие сопоставимые решения C ++ намного медленнее, чем printf. Если вы хотите заменить его на «лучшую» версию, вы нарушаете договор между языком и программистом и с самого начала находитесь в состоянии греха.
Алиса,
1
@Alice Хм, я не нарушаю никаких контрактов: std::printfis different from mynamespace::printf, и C ++ явно позволяет мне определять мои собственные функции, чьи имена дублируют имена функций внутри std. Это просто не подлежит обсуждению. Что касается ваших утверждений, которые printfэффективны из-за неправильного набора текста, это, конечно, тоже неверно. printfдаже не особенно эффективен, есть много более эффективных строго типизированных реализаций.
Конрад Рудольф
@KonradRudolph Абсолютно неверно; вы нарушаете контракт, записанный в стандарте, что printf без каких-либо квантификаторов явно применяется к конструкции C. Использование вами пространства имен с псевдонимом глобального пространства имен - не лучшая идея. Это просто не подлежит обсуждению .
Алиса
5
@Alice Не могли бы вы процитировать стандарт по этому поводу? Я не знаю такого словоблудия.
Конрад Рудольф
3

Из стандарта C ++ 11:

Каждый заголовок C, каждый из которых имеет имя формы name.h, ведет себя так, как если бы каждое имя, помещенное в пространство имен стандартной библиотеки соответствующим заголовком cname, помещалось в область глобального пространства имен. Не указано, были ли эти имена сначала объявлены или определены в области видимости пространства имен (3.3.6) пространства имен std, а затем введены в глобальную область пространства имен явными объявлениями using (7.3.3).

Итак, если вы используете <cstdio>, вы можете быть уверены, что printfон будет namespace stdв глобальном пространстве имен, а, следовательно, и не в нем.
Использование глобального пространства имен создает конфликт имен. Это не способ C ++.

Поэтому я использую <cstdio>заголовки и советую вам это сделать.

NeonMercury
источник
4
Хотя я бы хотел, чтобы это сработало, это неправда. Если вы включите, <cstdio>вы гарантируете, что std :: printf будет существовать, но нет никакой гарантии от стандарта if :: printf будет или не будет существовать. В самом деле, в каждом компиляторе я когда - либо слышал :: Printf будет введен в глобальное пространство имен при включении <cstdio>.
wjl
3

Из собственной практики: используйте std::префиксы. В противном случае один день abs будет укусить вас очень больно в случае , если вы используете плавающие точки.

Неквалифицированный absотносится к функции, определенной intна некоторых платформах. На других перегружено. Однако std::absвсегда перегружен для всех типов.

Eiennohito
источник
2

Использование только printfбез него std::может привести к конфликтам имен и считается плохой практикой многими разработчиками C ++. Google - ваш друг, но вот несколько ссылок, надеюсь, это поможет

Почему "использование пространства имен std" считается плохой практикой? http://www.cplusplus.com/forum/beginner/61121/

Разван
источник
4
using namespace std- плохая практика, но использование printfбез std::квалификатора - нет.
синтагма
using namespace std;это не моя проблема. Никогда не использую. printf();и std::printf();работать на C ++ без using namespace std;этого, поэтому я разместил вопрос.
DeiDei
@REACHUS Не согласен. Между двумя сценариями нет разницы.
Конрад Рудольф
Я бы никогда не стал std::printfего использовать, это просто странно.
тренки
@KonradRudolph Я не говорил, что есть разница, я просто высказал свое мнение (см. Мой ответ для более подробного обоснования).
синтагма
2

В stdio

Это версия C ++ заголовка стандартной библиотеки C @c stdio.h, и его содержимое (в основном) такое же, как этот заголовок, но все они содержатся в пространстве имен @c std (за исключением имен, которые определены как макросы в C).

Так что это не должно иметь никакого значения.

анукул
источник