Ao usar cabeçalhos C em C ++, devemos usar funções de std :: ou do namespace global?

113

C é, de certa forma, não exatamente, um subconjunto de C ++. Portanto, podemos usar a maioria das funções / cabeçalhos C em C ++ mudando um pouco o nome ( stdio.hpara cstdio, stdlib.hpara cstdlib).

Minha pergunta é meio semântica. No código C ++ (usando a versão mais recente do compilador GCC), posso chamar printf("Hello world!");e std::printf("Hello world!");funciona exatamente da mesma forma. E na referência que estou usando, também aparece como std::printf("Hello world!");.

Minha pergunta é: é preferível usar std::printf();em C ++? Existe alguma diferença?

DeiDei
fonte
17
No caso de um dia eles determinarem que o despejo de Csímbolos de biblioteca no namespace global seja ilegal, eu prefiro usar as std::versões qualificadas. (Além disso, eu meio que gostaria que eles tivessem tornado isso ilegal).
Galik
3
@Galik: Concordo. Isso evitaria muitas perguntas estúpidas sobre problemas de C usando um compilador C ++.
muito honesto para este site
7
Não existe "um pouco grávida". Ou C é um subconjunto ou não é. O fato é que não é . Essa é a razão pela qual os cabeçalhos C precisam ser modificados para funcionar em C ++.
muito honesto para este site
2
"quase todos" é uma medida bastante inútil quando falamos sobre um conjunto de muitos elementos incontáveis. Pelo mesmo argumento, você provavelmente poderia relacionar C e Java.
Daniel Jour
9
@sasauke não, não é um subconjunto. C e C ++ definitivamente compartilham um subconjunto, mas C em si não é um subconjunto de C ++.
O Croissant Paramagnético de

Respostas:

106

Do C ++ 11 Standard (ênfase minha):

Cabeçalhos de biblioteca padrão D.5 C [depr.c.headers]

  1. Para compatibilidade com a biblioteca padrão C ...
  2. Cada cabeçalho C, cada um com um nome no formato name.h , se comporta como se cada nome colocado no namespace da biblioteca padrão pelo cabeçalho cname correspondente fosse colocado no escopo do namespace global . Não é especificado se esses nomes são primeiro declarados ou definidos no escopo do namespace (3.3.6) do namespace std e, em seguida, são injetados no escopo do namespace global por declarações de uso explícitas (7.3.3).
  3. Exemplo: O cabeçalho <cstdlib> certamente fornece suas declarações e definições dentro do namespace std . Ele também pode fornecer esses nomes no namespace global. O cabeçalho <stdlib.h> certamente fornece as mesmas declarações e definições dentro do namespace global , assim como no C Standard. Ele também pode fornecer esses nomes no namespace std.

Usar os cabeçalhos «name.h» está obsoleto, eles foram identificados como candidatos para remoção de revisões futuras.

Então, eu sugeriria incluir os cabeçalhos «cname» e usar as declarações e definições do stdnamespace.

Se você tiver que usar os cabeçalhos «name.h» por alguns motivos (está obsoleto, veja acima), eu sugeriria usar as declarações e definições do namespace global.

Em outras palavras: prefira

#include <cstdio>

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

sobre

#include <stdio.h>

int main() {
    printf("Hello world\n");
}
Sergej
fonte
1
N3242 não é um padrão C ++. N3337 o rascunho com menos diferenças do C ++ 11.
MM de
3
Veja também Por que <cstdlib> é mais complicado do que você imagina nos blogs do Red hat, de Jonathan Wakely . Ele detalha uma série de problemas da perspectiva de um implementador de biblioteca padrão C ++. Ele também fornece um histórico que remonta ao C ++ 98.
jww
@sergej - Por acaso você conhece o tratamento do C ++ 03 sobre o assunto? Ou é um acerto ou erro o que vai acontecer?
jww
5
<name.h> pode estar obsoleto, não há chance de eles serem removidos tão cedo. Muito pelo contrário, na verdade. Há uma proposta para remover o rótulo obsoleto, consulte open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0619r0.html#3.5 . "Finalmente, parece claro que os cabeçalhos C serão retidos essencialmente para sempre, como uma camada de compatibilidade vital com C e POSIX. Pode valer a pena desprezar os cabeçalhos, [..]"
Sjoerd
82

<cmeow>sempre fornece ::std::purre pode ou não fornecer ::purr.

<meow.h>sempre fornece ::purre pode ou não fornecer ::std::purr.

Use o formulário que com certeza será fornecido pelo cabeçalho que você incluir.

TC
fonte
7
STL com um disfarce ruim?
nwp
@nwp não. (15 caracteres)
TC de
@TC Infelizmente, como eu tentei no meu compilador, nem <cmeow>nem <meow.h>fornece nem ::std::purrnem ::purr, mas sim um erro de pré-processador. Apenas <cstdio>e / ou <stdio.h>fornece ::std::printfe / ou ::printf. : P
LF
4
@LF Você pode precisar strcatproduzir ::purr.
Lundin,
8

Não, você está bem de qualquer maneira.

A intenção original era que os <___.h>cabeçalhos fossem as versões C que colocam tudo no namespace global, e os <c___>cabeçalhos seriam as versões C ++ ified, que colocam tudo no stdnamespace.

Na prática, porém, as versões C ++ também colocam tudo no namespace global. E não há um consenso claro de que usar as std::versões é "a coisa certa a fazer".

Então, basicamente, use o que você preferir. O mais comum é provavelmente usar as funções da biblioteca padrão C no namespace global (em printfvez de std::printf), mas não há muitos motivos para considerar uma "melhor" que a outra.

Jalf
fonte
2
"E não há um consenso claro de que usar std :: versions é" a coisa certa a fazer "." Sim, há um consenso absoluto de que essa é a coisa certa a se fazer.
Miles Rout
4
Como alguém determina objetivamente se o consenso foi ou não alcançado?
Jeremy Friesner
9
@JeremyFriesner você posta sobre isso no SO e vê se consegue comentários discordantes. :)
jalf
1
@JeremyFriesner: O padrão não garante que as versões do cabeçalho C ++ coloquem os identificadores no namespace global. O padrão também reprova as versões de cabeçalho C. Isso parece bastante consenso para mim. ;-)
DevSolar de
2
@DevSolar procure a palavra "consenso" em um dicionário, então. Não se trata do que o padrão diz, mas do que os programadores C ++ dizem - e especialmente, o que eles fazem . Há um motivo pelo qual literalmente toda implementação de biblioteca padrão fornece os cabeçalhos C e os cabeçalhos C ++ colocam tudo no namespace global também. :)
jalf
3

A única diferença é que, std::printf()ao adicionar std::resolução de escopo, você se protegerá de alguém que escreva uma função com o mesmo nome no futuro, o que levaria a um conflito de espaço de nomes. Ambos os usos levarão exatamente às mesmas chamadas de API do sistema operacional (você pode verificar no Linux executando strace your_program).

Acho muito improvável que alguém nomeie uma função assim, pois printf()é uma das funções mais comumente usadas por aí. Além disso, em C ++, iostreams são preferidos a chamadas de cstdiofunções como printf.

sintagma
fonte
1
Pelo contrário, acho bastante provável: printfestá gravemente quebrado em C ++ devido à sua falta de tipagem forte, substituí-lo por uma versão melhor é bastante natural.
Konrad Rudolph
1
@KonradRudolph Você pode descobrir dessa forma se quiser, mas está errado; não foi feito para ter uma digitação forte e há muitos problemas que não podem ser resolvidos facilmente com a digitação forte necessária. É por isso que muitas soluções C ++ comparáveis ​​são muito mais lentas do que printf. Se você quiser substituí-lo por uma versão "melhor", você está quebrando o contrato entre a linguagem e o programador e, para começar, está em estado de pecado.
Alice
1
@Alice Uhm, não estou quebrando nenhum contrato: std::printfé diferente de mynamespace::printf, e C ++ me permite explicitamente definir minhas próprias funções cujos nomes sombreiam as funções internas std. Isso simplesmente não é discutível. Quanto às suas afirmações que printfsão eficientes por causa da digitação solta, isso também está errado. printfnem mesmo é particularmente eficiente, existem muitas implementações mais eficientes que são fortemente tipadas.
Konrad Rudolph
@KonradRudolph Absolutamente incorreto; você está quebrando o contrato, escrito no padrão, que printf sem quaisquer quantificadores se aplica distintamente a uma construção C. O uso de um namespace, aliasing de namespace global, não é uma boa ideia. Isso simplesmente não é discutível .
Alice,
5
@Alice Você pode citar o padrão disso? Não estou ciente de tal verborragia.
Konrad Rudolph
3

Do padrão C ++ 11:

Cada cabeçalho C, cada um deles com um nome no formato name.h, se comporta como se cada nome colocado no namespace da biblioteca padrão pelo cabeçalho cname correspondente fosse colocado no escopo do namespace global. Não é especificado se esses nomes são primeiro declarados ou definidos no escopo do namespace (3.3.6) do namespace std e, em seguida, são injetados no escopo do namespace global por declarações de uso explícitas (7.3.3).

Portanto, se você usar <cstdio>, pode ter certeza de que printfestará no namespace stde, portanto, não no namespace global.
Usar um namespace global cria um conflito de nomes. Este não é o método C ++.

Portanto, estou usando <cstdio>cabeçalhos e aconselho você a fazer isso.

NeonMercury
fonte
4
Embora eu desejasse que funcionasse assim, isso não é verdade. Se você incluir, <cstdio>terá a garantia de que std :: printf existirá, mas não há garantia do padrão se :: printf existirá ou não também. Na verdade, em cada compilador que eu já ouvi falar, :: printf é injetado no namespace global quando você inclui <cstdio>.
wjl
3

Da minha própria prática: use std::prefixos. Caso contrário, um dia abs vai te morder muito dolorosamente no caso de você usar pontos flutuantes.

Não qualificado absrefere - se à função definida intem algumas plataformas. Em outros, está sobrecarregado. No entanto, std::absestá sempre sobrecarregado para todos os tipos.

Eiennohito
fonte
2

Usar apenas printfsem std::pode gerar alguns conflitos de nome e é considerado uma prática ruim por muitos desenvolvedores de c ++. O Google é seu amigo nisso, mas aqui estão alguns links, espero que isso ajude

Por que "usar o namespace std" é considerado uma prática ruim? http://www.cplusplus.com/forum/beginner/61121/

Razvan
fonte
4
using namespace stdé uma prática ruim, mas usar printfsem std::qualificador não é.
sintagma de
using namespace std;não é meu problema aqui. Eu nunca uso isso. printf();e std::printf();trabalhar em C ++ sem using namespace std;É por isso que postei a pergunta.
DeiDei
@REACHUS Discordo. Não há diferença entre os dois cenários.
Konrad Rudolph
Eu nunca usaria std::printfisso parece simplesmente estranho.
trenki
@KonradRudolph Eu não disse que há uma diferença, apenas expressei minha opinião (veja minha resposta para mais detalhes).
sintagma de
2

Em stdio

Esta é a versão C ++ do cabeçalho da Biblioteca C Padrão @c stdio.h, e seu conteúdo é (em sua maioria) igual ao cabeçalho, mas está todo contido no namespace @c std (exceto para nomes que são definidos como macros em C).

Portanto, não deve fazer nenhuma diferença.

anukul
fonte