Używając nagłówków C w C ++, czy powinniśmy używać funkcji z std :: czy globalnej przestrzeni nazw?

113

C jest w pewnym sensie, nie do końca, podzbiorem C ++. Więc możemy używać większości funkcji / nagłówków C w C ++, zmieniając nieco nazwę ( stdio.hna cstdio, stdlib.hna cstdlib).

Moje pytanie jest właściwie semantyczne. W kodzie C ++ (przy użyciu najnowszej wersji kompilatora GCC) mogę wywołać printf("Hello world!");i std::printf("Hello world!");działa dokładnie tak samo. W odnośniku, którego używam, pojawia się również jako std::printf("Hello world!");.

Moje pytanie brzmi, czy preferowane jest używanie std::printf();w C ++? Czy jest jakaś różnica?

DeiDei
źródło
17
W przypadku, gdy któregoś dnia nakazują zrzucanie Csymboli bibliotecznych do globalnej przestrzeni nazw, wolę używać std::wersji z uprawnieniami. (Poza tym żałuję, że nie zrobili tego nielegalnie).
Galik,
3
@Galik: Zgoda. To zabezpieczyłoby wiele głupich pytań dotyczących problemów z C przy użyciu kompilatora C ++.
zbyt szczera dla tej strony
7
Nie ma „trochę w ciąży”. Albo C jest podzbiorem, albo nie. Faktem jest, że tak nie jest . To jest powód, dla którego nagłówki C muszą zostać zmodyfikowane, aby działały w C ++.
zbyt szczera dla tej strony
2
„prawie wszystko” to dość bezużyteczna miara, gdy mówimy o zbiorze niezliczonej liczby elementów. Za pomocą tego samego argumentu prawdopodobnie można by powiązać C i Javę.
Daniel Jour
9
@sasauke nie, to nie jest podzbiór. C i C ++ zdecydowanie mają wspólny podzbiór, ale samo C nie jest podzbiorem C ++.
Rogalik Paramagnetyczny

Odpowiedzi:

106

Ze standardu C ++ 11 (wyróżnienie moje):

D.5 C nagłówki biblioteki standardowej [depr.c.headers]

  1. Aby zapewnić zgodność ze standardową biblioteką C ...
  2. Każdy nagłówek C, z których każdy ma nazwę w postaci nazwa.h , zachowuje się tak, jakby każda nazwa została umieszczona w przestrzeni nazw biblioteki standardowej przez odpowiednią nazwę cname nagłówek została umieszczona w zasięgu globalnej przestrzeni nazw . To jest określone, czy nazwy te są najpierw zadeklarowana lub zdefiniowana w zakresie przestrzeni nazw (3.3.6) z przestrzeni nazw std , a następnie wstrzykuje się do globalnej przestrzeni nazw przez zakres wyraźnych using-deklaracji (7.3.3).
  3. Przykład: nagłówek z <cstdlib> pewnością zawiera swoje deklaracje i definicje w przestrzeni nazw std . Może również udostępniać te nazwy w globalnej przestrzeni nazw. Nagłówek z <stdlib.h> pewnością zawiera te same deklaracje i definicje w globalnej przestrzeni nazw , podobnie jak w standardzie C. Może również udostępniać te nazwy w przestrzeni nazw std.

Używanie nagłówków „name.h” jest przestarzałe, zostały one zidentyfikowane jako kandydaci do usunięcia z przyszłych wersji.

Dlatego sugerowałbym dołączenie nagłówków „cname” oraz użycie deklaracji i definicji z stdprzestrzeni nazw.

Jeśli z jakichś powodów musisz używać nagłówków «name.h» (są one przestarzałe, zobacz powyżej), sugerowałbym użycie deklaracji i definicji z globalnej przestrzeni nazw.

Innymi słowy: preferuj

#include <cstdio>

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

nad

#include <stdio.h>

int main() {
    printf("Hello world\n");
}
sergej
źródło
1
N3242 nie jest żadnym standardem C ++. N3337 wersja robocza z najmniejszymi różnicami w stosunku do C ++ 11.
MM
3
Zobacz także artykuł Jonathana Wakely'ego Dlaczego <cstdlib> jest bardziej skomplikowany, niż mogłoby się wydawać na blogach Red hat. Opisuje szereg problemów z perspektywy implementującego bibliotekę standardową C ++. Przedstawia także historię sięgającą C ++ 98.
jww
@sergej - Czy znałbyś podejście C ++ 03 na ten temat? Czy może trafisz lub przegapisz, co się stanie?
jww
5
<name.h> może być przestarzałe, nie ma szans, że zostanie wkrótce usunięte. Wręcz przeciwnie. Istnieje propozycja usunięcia przestarzałej etykiety, patrz open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0619r0.html#3.5 . „Wreszcie wydaje się jasne, że nagłówki C zostaną zachowane zasadniczo na zawsze, jako istotna warstwa zgodności z C i POSIX. Może warto cofnąć uznanie nagłówków, [..]”
Sjoerd
82

<cmeow>zawsze zapewnia ::std::purri może lub nie zapewnia::purr .

<meow.h>zawsze zapewnia ::purri może lub nie zapewnia::std::purr .

Skorzystaj z formularza, który gwarantuje dołączony nagłówek.

TC
źródło
7
STL w kiepskim przebraniu?
nwp
@nwp nope. (15 znaków)
TC
@TC Niestety, jak próbowałem na moim kompilatorze, ani <cmeow>nie wyświetla <meow.h>ani, ::std::purrani ::purrraczej błędu preprocesora. Tylko <cstdio>i / lub <stdio.h>zapewnia ::std::printfi / lub ::printf. : P
LF
4
@LF Być może będziesz musiał strcatwyprodukować ::purr.
Lundin
8

Nie, wszystko w porządku.

Oryginalny intencją było to, że <___.h>nagłówki byłoby wersje C, który postawił wszystko w globalnej przestrzeni nazw, a <c___>nagłówki byłoby C ++ - Wersje IFIED, które miejsce wszystko w stdprzestrzeni nazw.

W praktyce jednak wersje C ++ również umieszczają wszystko w globalnej przestrzeni nazw. I nie ma jasnego konsensusu, że używanie std::wersji jest „właściwą rzeczą”.

Więc w zasadzie używaj tego, co wolisz. Najczęstszym jest prawdopodobnie użycie funkcji biblioteki standardowej C w globalnej przestrzeni nazw ( printfzamiast std::printf), ale nie ma powodu, aby uważać jedną „lepszą” od drugiej.

jalf
źródło
2
„I nie ma jasnego konsensusu, że używanie std :: Version jest„ właściwe ”. Uh, tak, istnieje absolutna zgoda co do tego, że należy to zrobić.
Miles Rout
4
Jak można obiektywnie określić, czy osiągnięto konsensus, czy też nie?
Jeremy Friesner
9
@JeremyFriesner, piszesz o tym na SO i sprawdzasz, czy otrzymujesz niezgodne komentarze. :)
jalf
1
@JeremyFriesner: Standard nie gwarantuje, że wersje nagłówków C ++ umieszczają identyfikatory w globalnej przestrzeni nazw. Standard unieważnia również wersje nagłówka C. Wydaje mi się to dość zgodne. ;-)
DevSolar
2
@DevSolar poszukaj w słowniku słowa „konsensus”. Nie chodzi o to, co mówi standard, ale co mówią programiści C ++ - a zwłaszcza, co robią . Jest powód , dla którego dosłownie każda implementacja biblioteki standardowej zawiera nagłówki C, a nagłówki C ++ również umieszczają wszystko w globalnej przestrzeni nazw. :)
jalf
3

Jedyna różnica polega na tym, że std::printf()dodając std::rozwiązywanie zakresu, zabezpieczysz się przed pisaniem funkcji o tej samej nazwie w przyszłości, co doprowadziłoby do konfliktu przestrzeni nazw. Oba zastosowania doprowadzą do dokładnie tych samych wywołań API systemu operacyjnego (możesz to sprawdzić pod Linuksem, uruchamiając strace your_program).

Uważam, że jest bardzo mało prawdopodobne, aby ktoś nazwał taką funkcję, ponieważ printf()jest to jedna z najczęściej używanych funkcji. Ponadto w C ++ iostreams są preferowane zamiast wywołań cstdiofunkcji takich jak printf.

syntagma
źródło
1
Wręcz przeciwnie, wydaje mi się to całkiem prawdopodobne: printfjest bardzo zepsuty w C ++ z powodu braku silnego pisania, zastąpienie go lepszą wersją jest całkiem naturalne.
Konrad Rudolph
1
@KonradRudolph Możesz to znaleźć w ten sposób, jeśli chcesz, ale byłbyś w błędzie; nie jest przeznaczone do silnego pisania i istnieje wiele problemów, których nie można łatwo rozwiązać za pomocą wymaganego silnego pisania. Dlatego wiele porównywalnych rozwiązań C ++ jest znacznie wolniejszych niż printf. Jeśli chcesz go zastąpić "lepszą" wersją, zrywasz kontrakt między językiem a programistą i jesteś w stanie grzechu.
Alice,
1
@Alice Uhm, nie zrywam żadnego kontraktu: std::printfróżni się od mynamespace::printf, a C ++ wyraźnie pozwala mi definiować własne funkcje, których nazwy stanowią cień tych z funkcji wewnątrz std. To po prostu nie podlega dyskusji. Jeśli chodzi o twoje twierdzenia, które printfsą wydajne z powodu luźnego pisania, oczywiście jest to również błędne. printfnie jest nawet szczególnie wydajne, istnieje wiele bardziej wydajnych implementacji, które są silnie wpisane.
Konrad Rudolph
@KonradRudolph Absolutnie niepoprawne; łamiesz kontrakt, zapisany w standardzie, że printf bez żadnych kwantyfikatorów ma wyraźne zastosowanie do konstrukcji C. Korzystanie z przestrzeni nazw, aliasowanie globalnej przestrzeni nazw, nie jest dobrym pomysłem. To po prostu nie podlega dyskusji .
Alice,
5
@Alice Czy możesz zacytować w tej sprawie standard? Nie znam takiego słownictwa.
Konrad Rudolph
3

Ze standardu C ++ 11:

Każdy nagłówek C, z których każdy ma nazwę w postaci nazwa.h, zachowuje się tak, jakby każda nazwa umieszczona w przestrzeni nazw biblioteki standardowej przez odpowiedni nagłówek cname została umieszczona w zasięgu globalnej przestrzeni nazw. Nie jest określone, czy te nazwy są najpierw zadeklarowane lub zdefiniowane w zakresie przestrzeni nazw (3.3.6) standardowej przestrzeni nazw, a następnie są wprowadzane do globalnego zakresu przestrzeni nazw przez jawne deklaracje using-declarations (7.3.3).

Więc jeśli używasz <cstdio>, możesz być pewien, że printfbędzie to w namespace std, a więc nie w globalnej przestrzeni nazw.
Używanie globalnej przestrzeni nazw powoduje konflikt nazw. To nie jest sposób C ++.

Dlatego używam <cstdio>nagłówków i radzę to zrobić.

NeonMercury
źródło
4
Chociaż chciałbym, żeby to działało w ten sposób, to nieprawda. Jeśli dołączysz, <cstdio>masz gwarancję, że std :: printf będzie istnieć, ale nie ma gwarancji ze strony standardu, czy :: printf również będzie istnieć lub nie będzie. W rzeczywistości, w każdym kompilatorze, o którym kiedykolwiek słyszałem, :: printf jest wstawiany do globalnej przestrzeni nazw, kiedy dołączasz <cstdio>.
wjl
3

Z mojej własnej praktyki: używaj std::przedrostków. W przeciwnym razie jeden dzień abs będzie cię ugryźć bardzo boleśnie w przypadku, gdy za pomocą punktów pływających.

Niekwalifikowany absodnosi się do funkcji zdefiniowanej intna niektórych platformach. Na innych jest przeciążony. Jednak std::absjest zawsze przeciążony dla wszystkich typów.

eiennohito
źródło
2

Używanie po prostu printfbez std::może generować konflikty nazw i jest uważane za złą praktykę przez wielu programistów C ++. Google jest twoim przyjacielem w tej sprawie, ale oto kilka linków, mam nadzieję, że to pomoże

Dlaczego „używanie std przestrzeni nazw” jest uważane za złą praktykę? http://www.cplusplus.com/forum/beginner/61121/

razvan
źródło
4
using namespace stdjest złą praktyką, ale używanie printfbez std::kwalifikatora nie.
syntagma
using namespace std;to nie jest mój problem. Nigdy tego nie używam. printf();i std::printf();pracować w C ++ bez using namespace std;Dlatego zadałem pytanie.
DeiDei
@REACHUS Nie zgadzam się. Nie ma różnicy między tymi dwoma scenariuszami.
Konrad Rudolph
Nigdy bym tego nie używał std::printf, wydaje się po prostu dziwne.
trenki
@KonradRudolph Nie powiedziałem, że jest różnica, po prostu wyraziłem swoją opinię (zobacz moją odpowiedź, aby uzyskać więcej powodów).
syntagma
2

W stdio

To jest wersja C ++ nagłówka standardowej biblioteki C @c stdio.h, a jego zawartość jest (w większości) taka sama jak ten nagłówek, ale wszystkie są zawarte w przestrzeni nazw @c std (z wyjątkiem nazw, które są zdefiniowane jako makra w DO).

Więc nie powinno to robić żadnej różnicy.

anukul
źródło