Al usar encabezados C en C ++, ¿deberíamos usar funciones de std :: o del espacio de nombres global?

113

C es algo, no exactamente, un subconjunto de C ++. Entonces podemos usar la mayoría de las funciones / encabezados de C en C ++ cambiando el nombre un poco ( stdio.ha cstdio,stdlib.h a cstdlib).

Mi pregunta es en realidad un poco semántica. En el código C ++ (usando la versión más reciente del compilador GCC), puedo llamar printf("Hello world!");y std::printf("Hello world!");funciona exactamente igual. Y en la referencia que estoy usando también aparece como std::printf("Hello world!");.

Mi pregunta es, ¿se prefiere usar std::printf();en C ++? ¿Hay una diferencia?

DeiDei
fuente
17
En el caso de que algún día exijan que el volcado de Csímbolos de la biblioteca en el espacio de nombres global sea ilegal, prefiero usar las std::versiones calificadas. (Además, desearía que lo hubieran hecho ilegal).
Galik
3
@Galik: De acuerdo. Eso evitaría muchas preguntas estúpidas sobre problemas de C utilizando un compilador de C ++.
demasiado honesto para este sitio
7
No hay "un poquito embarazada". C es un subconjunto o no lo es. El hecho es que no lo es . Esa es la razón por la que los encabezados C deben modificarse para que funcionen en C ++.
demasiado honesto para este sitio
2
"casi todos" es una medida bastante inútil cuando se habla de un conjunto de incontables elementos. Con el mismo argumento probablemente podría relacionar C y Java.
Daniel Jour
9
@sasauke no, no es un subconjunto. C y C ++ definitivamente comparten un subconjunto, pero C en sí mismo no es un subconjunto de C ++.
Croissant paramagnético del

Respuestas:

106

Del estándar C ++ 11 (el énfasis es mío):

D.5 Encabezados de biblioteca estándar de C [encabezados depr.c.]

  1. Para compatibilidad con la biblioteca estándar C ...
  2. Cada encabezado C, cada uno de los cuales tiene un nombre del formulario name.h , se comporta como si cada nombre colocado en el espacio de nombres de la biblioteca estándar por el encabezado cname correspondiente estuviera ubicado dentro del ámbito del espacio de nombres global . No se especifica si estos nombres se declaran o definen primero dentro del alcance del espacio de nombres (3.3.6) del espacio de nombres std y luego se inyectan en el alcance del espacio de nombres global mediante declaraciones de uso explícitas (7.3.3).
  3. Ejemplo: el encabezado <cstdlib> seguramente proporciona sus declaraciones y definiciones dentro del espacio de nombres std . También puede proporcionar estos nombres dentro del espacio de nombres global. El encabezado <stdlib.h> seguramente proporciona las mismas declaraciones y definiciones dentro del espacio de nombres global , como en el estándar C. También puede proporcionar estos nombres dentro del espacio de nombres std.

El uso de los encabezados «name.h» está en desuso, se han identificado como candidatos para ser eliminados de futuras revisiones.

Entonces, sugeriría incluir los encabezados «cname» y usar las declaraciones y definiciones del stdespacio de nombres.

Si tiene que usar los encabezados «name.h» por alguna razón (está desaprobado, vea arriba), sugeriría usar las declaraciones y definiciones del espacio de nombres global.

En otras palabras: prefiero

#include <cstdio>

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

encima

#include <stdio.h>

int main() {
    printf("Hello world\n");
}
sergej
fuente
1
N3242 no es un estándar C ++. N3337 el borrador con menos diferencias con C ++ 11.
MM
3
Vea también Por qué <cstdlib> de Jonathan Wakely es más complicado de lo que podría pensar en los blogs de Red Hat. Detalla una serie de problemas desde la perspectiva del implementador de una biblioteca estándar de C ++. También proporciona un historial que se remonta a C ++ 98.
jww
@sergej - ¿Conoces el tratamiento de C ++ 03 sobre el tema? ¿O es impredecible lo que sucederá?
jww
5
<name.h> podría estar obsoleto, no hay posibilidad de que se eliminen pronto. Todo lo contrario, de hecho. Existe una propuesta para eliminar la etiqueta obsoleta, consulte open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0619r0.html#3.5 . "Finalmente, parece claro que los encabezados C se conservarán esencialmente para siempre, como una capa de compatibilidad vital con C y POSIX. Puede valer la pena no predecir los encabezados, [..]"
Sjoerd
81

<cmeow>siempre proporciona ::std::purry puede o no proporcionar ::purr.

<meow.h>siempre proporciona ::purry puede o no proporcionar ::std::purr.

Utilice el formulario que garantiza el encabezado que incluye.

TC
fuente
7
¿STL mal disfrazado?
nwp
@nwp no. (15 caracteres)
TC
@TC Desafortunadamente, como probé en mi compilador, ni <cmeow>ni <meow.h>proporciona ni ::std::purrni, ::purrsino un error de preprocesador. Solo <cstdio>y / o <stdio.h>proporciona ::std::printfy / o ::printf. : P
LF
4
@LF Es posible que deba strcatproducir ::purr.
Lundin
8

No, estás bien de cualquier manera.

La intención original era que los <___.h>encabezados fueran las versiones de C que pusieran todo en el espacio de nombres global, y los <c___>encabezados serían las versiones de C ++, que colocan todo en el stdespacio de nombres.

En la práctica, sin embargo, las versiones de C ++ también colocan todo en el espacio de nombres global. Y no hay un consenso claro de que usar elstd:: versiones sea "lo correcto".

Entonces, básicamente, use el que prefiera. Lo más común es probablemente usar las funciones de la biblioteca estándar de C en el espacio de nombres global (en printflugar de std::printf), pero no hay muchas razones para considerar una "mejor" que la otra.

jalf
fuente
2
"Y no hay un consenso claro de que usar las versiones std :: sea" lo correcto "". Sí, hay un consenso absoluto de que es lo correcto.
Miles Rout
4
¿Cómo se determina objetivamente si se ha alcanzado o no consenso?
Jeremy Friesner
9
@JeremyFriesner lo publica en SO y ve si recibe comentarios en desacuerdo. :)
jalf
1
@JeremyFriesner: El estándar no garantiza que las versiones de encabezado de C ++ coloquen los identificadores en el espacio de nombres global. El estándar también desaprueba las versiones de encabezado C. Eso me parece bastante consenso. ;-)
DevSolar
2
@DevSolar busca la palabra "consenso" en un diccionario, entonces. No se trata de lo que dice el estándar, sino de lo que dicen los programadores de C ++ y, especialmente, de lo que hacen . Hay una razón por la que, literalmente, cada implementación de biblioteca estándar proporciona los encabezados C y los encabezados C ++ también colocan todo en el espacio de nombres global. :)
jalf
3

La única diferencia que hay es que std::printf()al agregar std::resolución de alcance, se protegerá de que alguien escriba una función con el mismo nombre en el futuro, lo que conduciría a un conflicto de espacio de nombres. Ambos usos conducirán a exactamente las mismas llamadas a la API del sistema operativo (puede verificarlo en Linux ejecutándolo strace your_program).

Me parece muy poco probable que alguien nombre una función así, ya que printf()es una de las funciones más utilizadas. Además, en C ++, iostreamse prefieren las llamadas a cstdiofunciones como printf.

sintagma
fuente
1
Por el contrario, lo encuentro bastante probable: printfestá muy roto en C ++ debido a su falta de escritura fuerte, reemplazarlo con una mejor versión es bastante natural.
Konrad Rudolph
1
@KonradRudolph Puedes encontrarlo de esa manera si quieres, pero estarías equivocado; no está diseñado para tener una escritura fuerte, y hay muchos problemas que no se pueden resolver fácilmente con la escritura fuerte requerida. Es por eso que muchas soluciones C ++ comparables son mucho más lentas que printf. Si desea reemplazarlo con una versión "mejor", está rompiendo el contrato entre el lenguaje y el programador y, para empezar, se encuentra en un estado de pecado.
Alice
1
@Alice Uhm, no estoy rompiendo ningún contrato: std::printfes diferente de mynamespace::printf, y C ++ explícitamente me permite definir mis propias funciones cuyos nombres sombrean los de las funciones internas std. Eso simplemente no es discutible. En cuanto a sus afirmaciones de que printfes eficiente debido a la escritura imprecisa, por supuesto también es incorrecto. printfni siquiera es particularmente eficiente, hay muchas implementaciones más eficientes que están fuertemente tipadas.
Konrad Rudolph
@KonradRudolph Absolutamente incorrecto; está rompiendo el contrato, escrito en el estándar, que printf sin ningún cuantificador se aplica claramente a una construcción C. El uso de un espacio de nombres, alias del espacio de nombres global, no es una buena idea. Eso simplemente no es discutible .
Alice
5
@Alice ¿Puedes citar el estándar sobre esto? No tengo conocimiento de tal palabrería.
Konrad Rudolph
3

Desde el estándar C ++ 11:

Cada encabezado C, cada uno de los cuales tiene un nombre del formulario name.h, se comporta como si cada nombre colocado en el espacio de nombres de la biblioteca estándar por el encabezado cname correspondiente estuviera ubicado dentro del ámbito del espacio de nombres global. No se especifica si estos nombres se declaran o definen primero dentro del alcance del espacio de nombres (3.3.6) del espacio de nombres std y luego se inyectan en el alcance del espacio de nombres global mediante declaraciones de uso explícitas (7.3.3).

Entonces, si lo usa <cstdio>, puede estar seguro de que printfestará en el namespace stdespacio de nombres global y, por lo tanto, no.
El uso de un espacio de nombres global crea un conflicto de nombres. Esta no es la forma de C ++.

Por lo tanto, estoy usando <cstdio>encabezados y le aconsejo que lo haga.

NeónMercurio
fuente
4
Aunque desearía que funcionara de esta manera, esto no es cierto. Si incluye <cstdio>, tiene la garantía de que std :: printf existirá, pero no hay garantía del estándar si :: printf también existirá o no. De hecho, en cada compilador del que he oído hablar, :: printf se inyecta en el espacio de nombres global cuando se incluye <cstdio>.
wjl
3

De mi propia práctica: use std::prefijos. De lo contrario, un día abs te morderá mucho en caso de que uses puntos flotantes.

No calificado se absrefiere a la función definida inten algunas plataformas. En otros está sobrecargado. Sin embargo, std::abssiempre está sobrecargado para todos los tipos.

eiennohito
fuente
2

Usar solo printfsinstd:: podría generar algunos conflictos de nombres y muchos desarrolladores de C ++ lo consideran una mala práctica. Google es tu amigo en este caso, pero aquí hay algunos enlaces, espero que esto ayude

¿Por qué se considera una mala práctica "utilizar el espacio de nombres estándar"? http://www.cplusplus.com/forum/beginner/61121/

razvan
fuente
4
using namespace stdes una mala práctica, pero usar printfsin std::calificador no lo es.
sintagma
using namespace std;no es mi problema aqui. Yo nunca lo uso. printf();y std::printf();trabajar en C ++ sin. using namespace std;Por eso publiqué la pregunta.
DeiDei
@REACHUS En desacuerdo. No hay diferencia entre los dos escenarios.
Konrad Rudolph
Nunca lo usaría, std::printfse siente simplemente extraño.
trenki
@KonradRudolph No dije que hubiera una diferencia, solo expresé mi opinión (vea mi respuesta para más razones).
sintagma
2

En stdio

Esta es la versión C ++ del encabezado de la biblioteca estándar C @c stdio.h, y su contenido es (en su mayoría) el mismo que ese encabezado, pero todos están contenidos en el espacio de nombres @c std (excepto los nombres que se definen como macros en C).

Entonces no debería hacer ninguna diferencia.

anukul
fuente