Quando si usano le intestazioni C in C ++, dovremmo usare le funzioni da std :: o lo spazio dei nomi globale?


113

C è un po ', non esattamente, un sottoinsieme di C ++. Quindi possiamo usare la maggior parte delle funzioni / intestazioni C in C ++ cambiando un po 'il nome ( stdio.hin cstdio, stdlib.hin cstdlib).

La mia domanda è in realtà una specie di semantica. Nel codice C ++ (utilizzando la versione più recente del compilatore GCC), posso chiamare printf("Hello world!");e std::printf("Hello world!");e funziona esattamente allo stesso modo. E nel riferimento che sto usando appare anche come std::printf("Hello world!");.

La mia domanda è: è preferibile utilizzare std::printf();in C ++? C'è una differenza?


17
Nel caso in cui un giorno impongano che il dumping dei Csimboli della libreria nello spazio dei nomi globale sia illegale, preferisco usare le std::versioni qualificate. (Inoltre, vorrei che l'avessero reso illegale).
Galik

3
@Galik: d'accordo. Ciò eviterebbe molte stupide domande sui problemi del C usando un compilatore C ++.
troppo onesto per questo sito

7
Non c'è "un po 'incinta". O C è un sottoinsieme o non lo è. Il fatto è che non lo è . Questo è il motivo per cui le intestazioni C devono essere modificate per funzionare in C ++.
troppo onesto per questo sito

2
"quasi tutto" è una misura abbastanza inutile quando si parla di un insieme di innumerevoli elementi. Con lo stesso argomento potresti probabilmente mettere in relazione C e Java.
Daniel Jour,

9
@sasauke no, non è un sottoinsieme. C e C ++ condividono sicuramente un sottoinsieme, ma il C stesso non è un sottoinsieme di C ++.
The Paramagnetic Croissant

Risposte:


106

Dallo standard C ++ 11 (enfasi mia):

D.5 Intestazioni della libreria standard C [depr.c.headers]

  1. Per compatibilità con la libreria standard C ...
  2. Ogni intestazione C, ognuna delle quali ha un nome nel formato name.h , si comporta come se ogni nome inserito nello spazio dei nomi della libreria standard dall'intestazione cname corrispondente fosse inserito nell'ambito dello spazio dei nomi globale . Non è specificato se questi nomi vengono prima dichiarati o definiti all'interno dell'ambito dello spazio dei nomi (3.3.6) dello spazio dei nomi std e vengono poi iniettati nell'ambito dello spazio dei nomi globale mediante dichiarazioni using esplicite (7.3.3).
  3. Esempio: l'intestazione fornisce <cstdlib> sicuramente le sue dichiarazioni e definizioni all'interno dello spazio dei nomi std . Può anche fornire questi nomi all'interno dello spazio dei nomi globale. L'intestazione fornisce <stdlib.h> sicuramente le stesse dichiarazioni e definizioni all'interno dello spazio dei nomi globale , proprio come nello standard C. Può anche fornire questi nomi all'interno dello spazio dei nomi std.

L'uso delle intestazioni «nome.h» è deprecato, sono state identificate come candidati per la rimozione da revisioni future.

Quindi, suggerirei di includere le intestazioni «cname» e di utilizzare le dichiarazioni e le definizioni dallo stdspazio dei nomi.

Se devi usare le intestazioni «name.h» per qualche motivo (è deprecato, vedi sopra), suggerirei di usare le dichiarazioni e le definizioni dallo spazio dei nomi globale.

In altre parole: preferisci

#include <cstdio>

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

al di sopra di

#include <stdio.h>

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

1
N3242 non è uno standard C ++. N3337 la bozza con meno differenze da C ++ 11.
MM

3
Vedi anche Perché <cstdlib> di Jonathan Wakely è più complicato di quanto potresti pensare dai blog di Red Hat. Descrive in dettaglio una serie di problemi dal punto di vista di un implementatore di librerie standard C ++. Fornisce anche una cronologia che risale a C ++ 98.
jww

@sergej - Ti capiterà di conoscere il trattamento C ++ 03 sull'argomento? O è colpito o perso quello che succederà?
jww

5
<name.h> potrebbe essere deprecato, non è possibile che vengano rimossi presto. Al contrario, in effetti. È disponibile una proposta per rimuovere l'etichetta obsoleta, vedere open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0619r0.html#3.5 . "Infine, sembra chiaro che le intestazioni C verranno conservate essenzialmente per sempre, come un livello di compatibilità vitale con C e POSIX. Potrebbe valere la pena annullare la definizione delle intestazioni, [..]"
Sjoerd

82

<cmeow>fornisce sempre ::std::purre può o non può fornire ::purr.

<meow.h>fornisce sempre ::purre può o non può fornire ::std::purr.

Utilizza il modulo che è garantito per essere fornito dall'intestazione che includi.


7
STL sotto mentite spoglie?
nwp

@nwp no. (15 caratteri)
TC

@TC Sfortunatamente, come ho provato sul mio compilatore, né <cmeow><meow.h>fornisce né ::std::purr::purrpiuttosto un errore del pre-processore. Solo <cstdio>e / o <stdio.h>fornisce ::std::printfe / o ::printf. : P
LF

4
@LF Potrebbe essere necessario strcatprodurre ::purr.
Lundin

8

No, stai bene comunque.

L' intento originale era che le <___.h>intestazioni fossero le versioni C che inseriscono tutto nello spazio dei nomi globale e le <c___>intestazioni sarebbero le versioni C ++ ified, che posizionano tutto nello stdspazio dei nomi.

In pratica, però, le versioni C ++ inseriscono anche tutto nello spazio dei nomi globale. E non c'è un chiaro consenso sul fatto che l'utilizzo delle std::versioni sia "la cosa giusta da fare".

Quindi, in pratica, usa quello che preferisci. Il più comune è probabilmente quello di utilizzare le funzioni della libreria standard C nello spazio dei nomi globale ( printfinvece di std::printf), ma non c'è motivo di considerarne una "migliore" dell'altra.


2
"E non c'è un chiaro consenso sul fatto che l'uso delle versioni std :: sia" la cosa giusta da fare "." Sì, c'è assolutamente consenso sul fatto che sia la cosa giusta da fare.
Miles Rout

4
Come si determina oggettivamente se è stato raggiunto o meno il consenso?
Jeremy Friesner

9
@ JeremyFriesner pubblichi qualcosa su SO e vedi se ricevi commenti in disaccordo. :)
jalf

1
@JeremyFriesner: lo standard non garantisce che le versioni dell'intestazione C ++ inseriscano gli identificatori nello spazio dei nomi globale. Lo standard depreca anche le versioni dell'intestazione C. Mi sembra abbastanza consensuale. ;-)
DevSolar

2
@DevSolar cerca la parola "consenso" in un dizionario, allora. Non si tratta di ciò che dice lo standard, ma di ciò che dicono i programmatori C ++ e soprattutto di ciò che fanno . C'è un motivo per cui letteralmente ogni implementazione di libreria standard fornisce le intestazioni C e le intestazioni C ++ mettono tutto anche nello spazio dei nomi globale. :)
jalf

3

L'unica differenza è che std::printf()aggiungendo la std::risoluzione dell'ambito ti proteggerai da qualcuno che scriva una funzione con lo stesso nome in futuro, il che porterebbe a un conflitto nello spazio dei nomi. Entrambi gli usi porteranno esattamente alle stesse chiamate API del sistema operativo (puoi verificarlo sotto Linux eseguendolo strace your_program).

Trovo molto improbabile che qualcuno chiami una funzione del genere, poiché printf()è una delle funzioni più comunemente utilizzate là fuori. Inoltre, in C ++, le iostreams sono preferite rispetto alle chiamate a cstdiofunzioni come printf.


1
Al contrario, lo trovo abbastanza probabile: printfè gravemente danneggiato in C ++ a causa della sua mancanza di battitura forte, sostituirlo con una versione migliore è abbastanza naturale.
Konrad Rudolph,

1
@KonradRudolph Puoi trovarlo in questo modo se vuoi, ma sbaglieresti; non è pensato per avere una digitazione forte e ci sono molti problemi che non possono essere risolti facilmente con la digitazione forte richiesta. Ecco perché molte soluzioni C ++ comparabili sono molto più lente di printf. Se vuoi sostituirlo con una versione "migliore", stai rompendo il contratto tra linguaggio e programmatore e sei in uno stato di peccato per cominciare.
Alice

1
@ Alice Uhm, non sto rompendo nessun contratto: std::printfè diverso da mynamespace::printf, e il C ++ mi permette esplicitamente di definire le mie funzioni i cui nomi ombreggiano quelli delle funzioni interne std. Semplicemente non è discutibile. Per quanto riguarda le tue affermazioni che printfsono efficienti a causa della digitazione allentata, ovviamente anche questo è sbagliato. printfnon è nemmeno particolarmente efficiente, ci sono molte implementazioni più efficienti che sono fortemente tipizzate.
Konrad Rudolph,

@KonradRudolph Assolutamente sbagliato; stai infrangendo il contratto, scritto nello standard, che printf senza quantificatori si applica distintamente a un costrutto C. L'utilizzo di uno spazio dei nomi, alias dello spazio dei nomi globale, non è una buona idea. Questo è non solo discutibili .
Alice

5
@Alice Puoi per favore citare lo standard su questo? Non sono a conoscenza di tale verbosità.
Konrad Rudolph,

3

Dallo standard C ++ 11:

Ogni intestazione C, ognuna delle quali ha un nome nel formato name.h, si comporta come se ogni nome inserito nello spazio dei nomi della libreria standard dall'intestazione cname corrispondente fosse inserito nell'ambito dello spazio dei nomi globale. Non è specificato se questi nomi vengono prima dichiarati o definiti all'interno dell'ambito dello spazio dei nomi (3.3.6) dello spazio dei nomi std e vengono quindi iniettati nell'ambito dello spazio dei nomi globale mediante dichiarazioni using esplicite (7.3.3).

Quindi, se usi <cstdio>, puoi essere sicuro che printfsarà namespace stdnello spazio dei nomi globale e quindi non nello spazio dei nomi.
L'utilizzo di uno spazio dei nomi globale crea un conflitto di nomi. Questo non è il modo C ++.

Pertanto, sto usando le <cstdio>intestazioni e ti consiglio di farlo.


4
Anche se vorrei che funzionasse in questo modo, non è vero. Se includi, <cstdio>hai la certezza che std :: printf esisterà, ma non c'è alcuna garanzia dallo standard se :: printf esisterà o meno. Infatti, in ogni compilatore di cui ho sentito parlare :: printf viene iniettato nello spazio dei nomi globale quando includi <cstdio>.
wjl

3

Dalla mia pratica: usa i std::prefissi. Altrimenti un giorno abs ti morderà molto dolorosamente nel caso in cui utilizzi punti mobili.

Non qualificato si absriferisce alla funzione definita intsu alcune piattaforme. Su altri è sovraccarico. Tuttavia std::absè sempre sovraccarico per tutti i tipi.


2

Usare solo printfsenza std::potrebbe generare alcuni conflitti di nome ed è considerata una cattiva pratica da molti sviluppatori di c ++. Google è tuo amico su questo, ma qui ci sono alcuni link, spero che questo aiuti

Perché "usare lo spazio dei nomi std" è considerato una cattiva pratica? http://www.cplusplus.com/forum/beginner/61121/


4
using namespace stdè una cattiva pratica, ma l'uso printfsenza std::qualificatore non lo è.
syntagma

using namespace std;non è un mio problema qui. Non lo uso mai. printf();e std::printf();lavorare in C ++ senza. using namespace std;Ecco perché ho postato la domanda.
DeiDei

@REACHUS Non sono d'accordo. Non c'è differenza tra i due scenari.
Konrad Rudolph,

Non lo userei mai std::printfsembra semplicemente strano.
trenki

@KonradRudolph Non ho detto che c'è una differenza, ho solo espresso la mia opinione (vedi la mia risposta per ulteriori motivazioni).
syntagma

2

In stdio

Questa è la versione C ++ dell'intestazione della libreria C standard @c stdio.h, e il suo contenuto è (per lo più) uguale all'intestazione, ma è tutto contenuto nello spazio dei nomi @c std (ad eccezione dei nomi che sono definiti come macro in C).

Quindi non dovrebbe fare alcuna differenza.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.