Lors de l'utilisation d'en-têtes C en C ++, devrions-nous utiliser des fonctions de std :: ou de l'espace de noms global?

113

C est un peu, pas exactement, un sous-ensemble de C ++. Nous pouvons donc utiliser la plupart des fonctions / en-têtes C en C ++ en changeant un peu le nom ( stdio.hto cstdio, stdlib.hto cstdlib).

Ma question est en fait un peu sémantique. En code C ++ (en utilisant la dernière version du compilateur GCC), je peux appeler printf("Hello world!");et std::printf("Hello world!");et cela fonctionne exactement de la même manière. Et dans la référence que j'utilise, il apparaît également sous la forme std::printf("Hello world!");.

Ma question est la suivante: est-il préférable d'utiliser std::printf();en C ++? Y a-t-il une différence?

DeiDei
la source
17
Dans le cas où un jour ils imposeraient le dumping de Csymboles de bibliothèque dans l'espace de noms global soit illégal, je préfère utiliser les std::versions qualifiées. (De plus, j'aurais aimé qu'ils l'aient rendu illégal).
Galik
3
@Galik: D'accord. Cela sécuriserait beaucoup de questions stupides sur les problèmes C en utilisant un compilateur C ++.
trop honnête pour ce site
7
Il n'y a pas de "un peu enceinte". Soit C est un sous-ensemble, soit il ne l'est pas. Le fait est que ce n'est pas le cas . C'est la raison pour laquelle les en-têtes C doivent être modifiés pour fonctionner en C ++.
trop honnête pour ce site
2
"presque tout" est une mesure assez inutile quand on parle d'un ensemble de nombreux éléments innombrables. Par le même argument, vous pourriez probablement relier C et Java.
Daniel Jour
9
@sasauke non, ce n'est pas un sous-ensemble. C et C ++ partagent définitivement un sous-ensemble, mais C lui - même n'est pas un sous-ensemble de C ++.
Le Croissant Paramagnétique

Réponses:

106

De la norme C ++ 11 (c'est moi qui souligne):

D.5 En-têtes de bibliothèque standard C [depr.c.headers]

  1. Pour la compatibilité avec la bibliothèque standard C ...
  2. Chaque en-tête C, dont chacun a un nom du formulaire name.h , se comporte comme si chaque nom placé dans l'espace de noms de bibliothèque standard par l'en- tête cname correspondant était placé dans la portée de l' espace de noms global . Il n'est pas précisé si ces noms sont d'abord déclarés ou définis dans la portée d'espace de noms (3.3.6) de l'espace de noms std et sont ensuite injectés dans la portée d'espace de noms global par des déclarations d'utilisation explicites (7.3.3).
  3. Exemple: l'en-tête fournit <cstdlib> assurément ses déclarations et définitions dans l'espace de noms std . Il peut également fournir ces noms dans l'espace de noms global. L'en-tête fournit <stdlib.h> assurément les mêmes déclarations et définitions dans l'espace de noms global , tout comme dans le C Standard. Il peut également fournir ces noms dans l'espace de noms std.

L'utilisation des en-têtes «name.h» est obsolète, ils ont été identifiés comme candidats à la suppression des futures révisions.

Donc, je suggérerais d'inclure les en-têtes «cname» et d'utiliser les déclarations et définitions de l' stdespace de noms.

Si vous devez utiliser les en-têtes «name.h» pour certaines raisons (c'est obsolète, voir ci-dessus), je vous suggère d'utiliser les déclarations et définitions de l'espace de noms global.

En d'autres termes: préférez

#include <cstdio>

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

plus de

#include <stdio.h>

int main() {
    printf("Hello world\n");
}
Sergej
la source
1
N3242 n'est pas un standard C ++. N3337 le projet avec le moins de différences avec C ++ 11.
MM
3
Voir aussi Why <cstdlib> de Jonathan Wakely est plus compliqué que vous ne le pensez sur les blogs Red Hat. Il détaille un certain nombre de problèmes du point de vue d'un implémenteur de bibliothèque standard C ++. Il fournit également un historique remontant à C ++ 98.
jww
@sergej - Connaissez-vous le traitement C ++ 03 sur le sujet? Ou est-ce que ce qui va se passer est aléatoire?
jww
5
<name.h> pourrait être obsolète, il n'y a aucune chance qu'ils soient supprimés de sitôt. Plutôt l'inverse, en fait. Il existe une proposition de suppression de l'étiquette obsolète, voir open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0619r0.html#3.5 . "Enfin, il semble clair que les en-têtes C seront conservés essentiellement pour toujours, en tant que couche de compatibilité vitale avec C et POSIX. Cela peut valoir la peine de déprécier les en-têtes, [..]"
Sjoerd
82

<cmeow>fournit toujours ::std::purret peut ou ne peut pas fournir ::purr.

<meow.h>fournit toujours ::purret peut ou ne peut pas fournir ::std::purr.

Utilisez le formulaire qui est garanti fourni par l'en-tête que vous incluez.

TC
la source
7
STL mal déguisé?
nwp
@nwp non. (15 caractères)
TC
@TC Malheureusement, comme j'ai essayé sur mon compilateur, ni <cmeow>ni <meow.h>ne fournit ni ::std::purrni ::purrmais plutôt une erreur de pré-processeur. Seulement <cstdio>et / ou <stdio.h>fournit ::std::printfet / ou ::printf. : P
LF
4
@LF Vous devrez peut-être strcatproduire ::purr.
Lundin
8

Non, tu vas bien de toute façon.

L' intention originale était que les en- <___.h>têtes seraient les versions C qui mettraient tout dans l'espace de noms global, et les en- <c___>têtes seraient les versions C ++, qui placent tout dans l' stdespace de noms.

En pratique, cependant, les versions C ++ placent également tout dans l'espace de noms global. Et il n'y a pas de consensus clair sur le fait que l'utilisation dustd:: versions est "la bonne chose à faire".

Donc, en gros, utilisez celui que vous préférez. Le plus courant est probablement d'utiliser les fonctions de la bibliothèque standard C dans l'espace de noms global ( printfau lieu de std::printf), mais il n'y a pas beaucoup de raisons de considérer l'une comme "meilleure" que l'autre.

jalf
la source
2
"Et il n'y a pas de consensus clair sur le fait que l'utilisation des versions std :: est" la bonne chose à faire "." Euh, oui, il y a absolument un consensus sur le fait que c'est la bonne chose à faire.
Miles Rout
4
Comment déterminer objectivement si un consensus a été atteint ou non?
Jeremy Friesner
9
@JeremyFriesner vous postez à ce sujet sur SO et voyez si vous obtenez des commentaires en désaccord. :)
jalf
1
@JeremyFriesner: La norme ne garantit pas que les versions d'en-tête C ++ placent les identificateurs dans l'espace de noms global. La norme désapprouve également les versions d'en-tête C. Cela me semble assez consensuel. ;-)
DevSolar
2
@DevSolar cherche alors le mot «consensus» dans un dictionnaire. Il ne s'agit pas de ce que dit la norme, mais de ce que disent les programmeurs C ++ - et surtout, de ce qu'ils font . Il y a une raison pour laquelle chaque implémentation de bibliothèque standard fournit les en-têtes C et que les en-têtes C ++ mettent tout dans l'espace de noms global. :)
jalf
3

La seule différence est qu'en std::printf()ajoutant une std::résolution de portée, vous vous sécuriserez contre quelqu'un qui écrit une fonction avec le même nom à l'avenir, ce qui entraînerait un conflit d'espace de noms. Les deux utilisations conduiront exactement aux mêmes appels d'API OS (vous pouvez le vérifier sous Linux en exécutantstrace your_program ).

Je trouve très improbable que quelqu'un nomme une fonction comme celle-là, comme printf()c'est l'une des fonctions les plus couramment utilisées. De plus, en C ++, les iostreams sont préférables aux appels à des cstdiofonctions comme printf.

syntagme
la source
1
Au contraire, je le trouve assez probable: printfest gravement cassé en C ++ en raison de son manque de frappe forte, le remplacer par une meilleure version est tout à fait naturel.
Konrad Rudolph
1
@KonradRudolph Vous pouvez le trouver de cette façon si vous le souhaitez, mais vous vous trompez; il n'est pas censé avoir un typage fort, et il existe de nombreux problèmes qui ne peuvent pas être résolus facilement avec le typage fort requis. C'est pourquoi de nombreuses solutions C ++ comparables sont beaucoup plus lentes que printf. Si vous voulez le remplacer par une version "meilleure", vous rompez le contrat entre le langage et le programmeur, et vous êtes dans un état de péché pour commencer.
Alice le
1
@Alice Euh, je ne romps aucun contrat: std::printfest différent de mynamespace::printf, et C ++ me permet explicitement de définir mes propres fonctions dont les noms reflètent ceux des fonctions à l'intérieurstd . Ce n'est tout simplement pas discutable. Quant à vos affirmations qui printfsont efficaces en raison d'une frappe lâche, c'est bien sûr également erroné. printfn'est même pas particulièrement efficace, il existe de nombreuses implémentations plus efficaces qui sont fortement typées.
Konrad Rudolph
@KonradRudolph Absolument incorrect; vous rompez le contrat, écrit dans la norme, que printf sans aucun quantificateur s'applique distinctement à une construction C. Votre utilisation d'un espace de noms, en créant un alias pour l'espace de noms global, n'est pas une bonne idée. Ce n'est tout simplement pas discutable .
Alice
5
@Alice Pouvez-vous citer la norme à ce sujet? Je ne suis pas au courant d'un tel verbiage.
Konrad Rudolph
3

À partir de la norme C ++ 11:

Chaque en-tête C, dont chacun a un nom du formulaire name.h, se comporte comme si chaque nom placé dans l'espace de noms de bibliothèque standard par l'en-tête cname correspondant était placé dans la portée de l'espace de noms global. Il n'est pas précisé si ces noms sont d'abord déclarés ou définis dans la portée d'espace de noms (3.3.6) de l'espace de noms std et sont ensuite injectés dans la portée d'espace de noms global par des déclarations d'utilisation explicites (7.3.3).

Donc, si vous utilisez <cstdio>, vous pouvez être sûr que ce printfsera dans namespace std, et donc pas dans l'espace de noms global.
L'utilisation d'un espace de noms global crée un conflit de noms. Ce n'est pas une manière C ++.

Par conséquent, j'utilise des en- <cstdio>têtes et je vous conseille de le faire.

NéonMercure
la source
4
Bien que je souhaite que cela fonctionne de cette façon, ce n'est pas vrai. Si vous incluez, <cstdio>vous avez la garantie que std :: printf existera, mais il n'y a aucune garantie de la norme si :: printf existera ou non aussi. En fait, dans tous les compilateurs dont j'ai entendu parler :: printf est injecté dans l'espace de noms global lorsque vous incluez <cstdio>.
wjl
3

De ma propre pratique: utilisez des std::préfixes. Sinon un jourabs sera vous mordre très douloureusement au cas où vous en utilisant des points flottants.

Non qualifié absfait référence à la fonction définie intsur certaines plates-formes. Sur d'autres, il est surchargé. Cependant std::absest toujours surchargé pour tous les types.

eiennohito
la source
2

Utiliser juste printfsans std::pourrait générer des conflits de nom et est considéré comme une mauvaise pratique par de nombreux développeurs C ++. Google est votre ami sur celui-ci, mais voici quelques liens, j'espère que cela vous aidera

Pourquoi "utiliser l'espace de noms std" est-il considéré comme une mauvaise pratique? http://www.cplusplus.com/forum/beginner/61121/

Rasvan
la source
4
using namespace stdest une mauvaise pratique mais l'utilisation printfsans std::qualificatif ne l'est pas.
syntagma
using namespace std;ce n'est pas mon problème ici. Je ne l'utilise jamais. printf();et std::printf();travailler en C ++ sans using namespace std;C'est pourquoi j'ai posté la question.
DeiDei
@REACHUS Pas d'accord. Il n'y a aucune différence entre les deux scénarios.
Konrad Rudolph
Je ne l'utiliserais jamais, std::printfcela semble tout simplement étrange.
trenki
@KonradRudolph Je n'ai pas dit qu'il y avait une différence, j'ai juste exprimé mon opinion (voir ma réponse pour plus de raisons).
syntagma
2

Dans stdio

Il s'agit de la version C ++ de l'en-tête de la bibliothèque C Standard @c stdio.h, et son contenu est (pour la plupart) le même que cet en-tête, mais sont tous contenus dans l'espace de noms @c std (à l'exception des noms définis comme des macros dans C).

Cela ne devrait donc pas faire de différence.

anukul
la source