Якщо ми використовуємо заголовки 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 ++? Чи є різниця?


17
У випадку, якщо одного дня вони зобов’язують скидання Cбібліотечних символів у глобальний простір імен незаконним, я вважаю за краще використовувати std::кваліфіковані версії. (Плюс я бажаю, щоб вони зробили це незаконним).
Галик

3
@Galik: Погоджено. Це дозволило б захистити багато дурних питань щодо проблем C за допомогою компілятора C ++.
занадто чесний для цього сайту

7
Немає "трохи вагітної". Або C - це підмножина, або це не так. Факт, це не так . Саме тому заголовки C повинні бути змінені для роботи в C ++.
занадто чесний для цього сайту

2
"майже всі" - досить марний захід, коли йдеться про набір незліченних безлічі елементів. За тим же аргументом ви могли, мабуть, пов’язати C та Java.
Даніель Жур

9
@sasauke ні, це не підмножина. C і C ++, безумовно, поділяють підмножину, але сам C не є підмножиною C ++.
Парамагнітний круасан

Відповіді:


106

Із стандарту C ++ 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");
}

1
N3242 не є будь-яким стандартом C ++. N3337 проект з найменшими відмінностями від C ++ 11.
ММ

3
Також дивіться " Чому <cstdlib>" Джонатана Уейклі складніше, ніж можна подумати, з блогів "Червона шапочка". Він детально описує низку проблем з точки зору впровадника стандартної бібліотеки C ++. Він також пропонує історію, що повертається до C ++ 98.
jww

@sergej - Чи трапляється вам знати про лікування C ++ 03 з цього приводу? Або вдарив або пропустив, що станеться?
jww

5
<name.h> може бути застарілим, немає шансів, що вони незабаром будуть видалені. Насправді навпаки. Існує пропозиція про видалення застарілої мітки, див. Open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0619r0.html#3.5 . "Нарешті, здається очевидним, що заголовки C зберігатимуться по суті назавжди, як життєво важливий рівень сумісності із C та POSIX. Можливо, варто недооцінювати заголовки, [..]"
Sjoerd

82

<cmeow>завжди надає ::std::purrта може надавати або не може ::purr.

<meow.h>завжди надає ::purrта може надавати або не може ::std::purr.

Використовуйте форму, яку гарантовано надаватимете заголовок, який ви включаєте.


7
STL в поганій маскуванні?
nwp

@nwp nope. (15 годин)
ТК

@TC На жаль, як я намагався на своєму компіляторі, ні <cmeow>ні не <meow.h>надає ні, ::std::purrні, ::purrа скоріше помилка перед процесором. Тільки <cstdio>та / або <stdio.h>надає ::std::printfта / або ::printf. : P
LF

4
@LF Можливо, вам strcatдоведеться виготовити ::purr.
Лундін

8

Ні, у будь-якому випадку ви все добре.

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

На практиці, однак, версії C ++ також все вкладають у глобальний простір імен. І немає чіткого консенсусу, що використання std::версій - це "правильна річ".

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


2
"І немає чіткого консенсусу, що використання версій std :: - це" правильна справа "." Так, абсолютно існує консенсус, що це правильно робити.
Майлз Рут

4
Як можна об'єктивно визначити, чи досягнуто консенсусу чи ні?
Джеремі Фріснер

9
@JeremyFriesner ви публікуєте інформацію про це та бачите, чи отримуєте ви незгодні коментарі. :)
jalf

1
@JeremyFriesner: Стандарт не гарантує, що версії заголовків C ++ ставлять ідентифікатори в глобальному просторі імен. Стандарт також застарає версії заголовка C. Це виглядає для мене досить консенсусом. ;-)
DevSolar

2
@DevSolar шукайте слово "консенсус" у словнику, потім. Йдеться не про те, що говорить стандарт, а те, що кажуть програмісти C ++ - і особливо, що вони роблять . Існує причина, що буквально кожна стандартна реалізація бібліотеки забезпечує заголовки C, а заголовки C ++ також містять все у глобальному просторі імен. :)
jalf

3

Єдина відмінність полягає в тому, що std::printf(), додавши std::роздільну здатність області, ви захистите себе від того, хто пише функцію з тим самим іменем у майбутньому, що призведе до конфлікту в просторі імен. Обидві звичаї призводять до однакових викликів API OS (ви можете перевірити це в Linux, запустивши strace your_program).

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


1
Навпаки, я вважаю це цілком вірогідним: printfсильно зламаний в C ++ через відсутність сильного набору тексту, замінити його на кращу версію цілком природно.
Конрад Рудольф

1
@KonradRudolph Ви можете знайти саме так, якщо вам подобається, але ви помилитесь; це не призначено для сильного набору тексту, і є багато проблем, які неможливо легко вирішити за допомогою потрібного сильного введення тексту. Ось чому багато порівнянні рішення C ++ набагато повільніше, ніж printf. Якщо ви хочете замінити його на "кращу" версію, ви розриваєте договір між мовою та програмістом, і ви перебуваєте в гріху.
Аліса

1
@Alice Uhm, я не порушую жодного контракту: std::printfвідрізняється від mynamespace::printf, і C ++ явно дозволяє мені визначати власні функції, імена яких відтіняють ті від функцій всередині std. Це просто не дискусійно. Що стосується ваших тверджень, які printfє ефективними через слабкий набір тексту, це, звичайно, також неправильно. printfНе є навіть особливо ефективною, є багато більш ефективних реалізацій, які сильно набрані.
Конрад Рудольф

@KonradRudolph Абсолютно неправильно; Ви порушуєте контракт, написаний у стандарті, що printf без жодних кванторів чітко застосовується до конструкції C. Використання простору імен, за допомогою прізвища глобального простору імен, не є хорошою ідеєю. Це просто не дискусійно .
Аліса

5
@Alice Чи можете ви процитувати цей стандарт? Я не знаю жодної такої багатослівності.
Конрад Рудольф

3

Зі стандарту C ++ 11:

Кожен заголовок C, кожен з яких має назву форми name.h, поводиться так, ніби кожне ім'я, розміщене в стандартному просторі імен бібліотеки відповідним заголовком імен, розміщене в межах глобального простору імен. Не визначено, чи спочатку ці імена декларуються або визначаються в межах простору імен (3.3.6) простору імен std і потім вводяться в глобальну область простору імен шляхом явного використання декларацій (7.3.3).

Отже, якщо ви використовуєте <cstdio>, ви можете бути впевнені, що printfце буде namespace stdу глобальному просторі імен, а отже, і не.
Використання глобального простору імен створює конфлікт імен. Це не спосіб С ++.

Тому я використовую <cstdio>заголовки і раджу це зробити.


4
Хоча я б хотів, щоб це працювало так, це неправда. Якщо ви включите, <cstdio>ви гарантуєтесь, що std :: printf буде існувати, але немає гарантії від стандарту, якщо :: printf також буде існувати. Справді, в кожному компіляторі я коли - небудь чув :: Printf буде введений в глобальний простір імен при включенні <cstdio>.
wjl

3

З моєї власної практики: використовуйте std::префікси. В іншому випадку один день abs буде вкусити вас дуже боляче в разі , якщо ви використовуєте плаваючі точки.

Некваліфікований absвідноситься до функції, визначеної intна деяких платформах. На інших це перевантажено. Однак std::absзавжди перевантажений для всіх типів.


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

В стдіо

Це версія C ++ заголовка стандартної бібліотеки C @c stdio.h, і його вміст (здебільшого) такий же, як у заголовку, але весь він міститься у просторі імен @c std (за винятком імен, які визначені як макроси у В).

Тож це не повинно мати жодних змін.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.