Nos primeiros dias do C ++, quando ele era aparafusado em cima de C, não era possível usar NULL como definido (void*)0
. Você não pode atribuir NULL a nenhum ponteiro além de void*
, o que o tornou meio inútil. Naqueles dias, era aceito que você usasse 0
(zero) para ponteiros nulos.
Até hoje, continuei usando zero como ponteiro nulo, mas aqueles que estão à minha volta insistem em usá-lo NULL
. Pessoalmente, não vejo nenhum benefício em atribuir um nome ( NULL
) a um valor existente - e como também gosto de testar ponteiros como valores verdadeiros:
if (p && !q)
do_something();
então, usar zero faz mais sentido (como se você usar NULL
, não é possível usar logicamente p && !q
- você precisa comparar explicitamente NULL
, a menos que assuma que NULL
é zero; nesse caso, por que usar NULL
).
Existe alguma razão objetiva para preferir zero a NULL (ou vice-versa), ou é apenas preferência pessoal?
Editar: devo adicionar (e pretendia dizer originalmente) que, com RAII e exceções, raramente uso ponteiros zero / NULL, mas às vezes você ainda precisa deles.
Respostas:
Aqui está a opinião de Stroustrup sobre isso: Perguntas frequentes sobre estilo e técnica em C ++
Dito isto, não se preocupe com as pequenas coisas.
fonte
Existem alguns argumentos (um dos quais é relativamente recente) que acredito contradizerem a posição de Bjarne sobre isso.
O uso
NULL
permite pesquisas sobre seu uso e também destaca que o desenvolvedor queria usar umNULL
ponteiro, independentemente de ele estar sendo interpretadoNULL
ou não pelo compilador .O exemplo que todo mundo cita é:
No entanto, pelo menos na minha opinião, o problema com o exposto acima não é que estamos usando NULL para a constante de ponteiro nulo, é que temos sobrecargas de 'foo' que usam tipos de argumentos muito diferentes. O parâmetro também deve ser um
int
, pois qualquer outro tipo resultará em uma chamada ambígua e, portanto, gerará um aviso útil do compilador.Mesmo na ausência de C ++ 0x, existem ferramentas disponíveis hoje que verificam se
NULL
está sendo usado para ponteiros e se0
está sendo usado para tipos integrais.std::nullptr_t
tipo.Este é o argumento mais recente da tabela. O problema de
0
eNULL
está sendo tratado ativamente no C ++ 0x, e você pode garantir que, para cada implementação que forneçaNULL
, a primeira coisa que eles farão é:Para aqueles que usam
NULL
em vez de0
, a mudança será uma melhoria no tipo de segurança com pouco ou nenhum esforço - se alguma coisa ele também pode pegar alguns bugs onde eles utilizadosNULL
para0
. Para quem usa0
hoje ... bem ... espero que eles tenham um bom conhecimento de expressões regulares ...fonte
#include
e mantenha o lado seguro o tempo todo.#define NULL nullptr
parece perigoso. Para melhor ou pior, muitos códigos herdados usam NULL para outras coisas que não sejam 0. Por exemplo, os identificadores são frequentemente implementados como algum tipo integral, e configurá-los comoNULL
não é incomum. Eu já vi abusos como usarNULL
para definir umchar
para um terminador zero.NULL
estão realmente incorretos. Muitas APIs são usadas há muito tempoNULL
com alças, e esse é realmente o uso documentado de muitas delas. Não é pragmático quebrá-los de repente e declarar que eles estão fazendo errado.Use NULL. NULL mostra sua intenção. O fato de ser 0 é um detalhe de implementação que não deve importar.
fonte
Eu sempre uso:
NULL
para ponteiros'\0'
para caracteres0.0
para carros alegóricos e duplosonde 0 faria bem. É uma questão de sinalizar intenção. Dito isto, eu não sou anal sobre isso.
fonte
Parei de usar NULL em favor de 0 há muito tempo (assim como a maioria das outras macros). Fiz isso não apenas porque queria evitar o máximo possível de macros, mas também porque NULL parece ter sido superutilizado no código C e C ++. Parece ser usado sempre que um valor 0 é necessário, não apenas para ponteiros.
Em novos projetos, coloquei isso no cabeçalho do projeto:
Agora, quando chegam os compiladores compatíveis com C ++ 0x, tudo o que preciso fazer é remover essa linha. Uma boa vantagem disso é que o Visual Studio já reconhece o nullptr como uma palavra-chave e o destaca adequadamente.
fonte
A moral da história. Você deve usar NULL quando estiver lidando com ponteiros.
1) Declara sua intenção (não me faça pesquisar em todo o seu código tentando descobrir se uma variável é um ponteiro ou algum tipo numérico).
2) Em determinadas chamadas de API que esperam argumentos variáveis, eles usarão um ponteiro NULL para indicar o final da lista de argumentos. Nesse caso, usar um '0' em vez de NULL pode causar problemas. Em uma plataforma de 64 bits, a chamada va_arg deseja um ponteiro de 64 bits, mas você passará apenas um número inteiro de 32 bits. Parece-me que você está confiando nos outros 32 bits para ser zerado para você? Eu vi alguns compiladores (por exemplo, icpc da Intel) que não são tão gentis - e isso resultou em erros de tempo de execução.
fonte
NULL
talvez não seja portátil e não seja seguro. Pode haver plataformas que ainda#define NULL 0
(de acordo com a FAQ do Stroustrup: Devo usar NULL ou 0? Citado pela pergunta principal e ele está entre os primeiros resultados da pesquisa). Pelo menos no C ++ mais antigo,0
tem um significado conceitual especial no contexto do ponteiro. Você não deve pensar concretamente em bits. Observe também que em diferentes contextos inteiros (short
,int
,long long
) "sizeof(0)
" vai ser diferente. Eu acho que essa resposta é um pouco equivocada.NULL
vez de(char *)0
,(const char *)0
ou(struct Boo *)0
ou(void *)0
ou o que quer, expressar a intenção com mais clareza - sem ser (na minha opinião) muito complicado.)Se bem me lembro, NULL é definido de maneira diferente nos cabeçalhos que usei. Para C, é definido como (void *) 0, e para C ++, é definido como apenas 0. O código se parecia com:
Pessoalmente, ainda uso o valor NULL para representar ponteiros nulos, deixando explícito que você está usando um ponteiro em vez de algum tipo integral. Sim internamente, o valor NULL ainda é 0, mas não é representado como tal.
Além disso, não confio na conversão automática de números inteiros em valores booleanos, mas os comparo explicitamente.
Por exemplo, prefira usar:
ao invés de:
Basta dizer que tudo isso é remediado no C ++ 11, onde se pode simplesmente usar em
nullptr
vez deNULL
, e tambémnullptr_t
esse é o tipo de anullptr
.fonte
Eu diria que a história falou e aqueles que argumentaram a favor do uso de 0 (zero) estavam errados (incluindo Bjarne Stroustrup). Os argumentos a favor de 0 eram principalmente estética e "preferência pessoal".
Após a criação do C ++ 11, com seu novo tipo nullptr, alguns compiladores começaram a reclamar (com parâmetros padrão) sobre a passagem de 0 para funções com argumentos de ponteiro, porque 0 não é um ponteiro.
Se o código tivesse sido escrito usando NULL, uma simples pesquisa e substituição poderia ter sido realizada através da base de código para torná-lo nullptr. Se você está preso ao código escrito usando a opção 0 como ponteiro, é muito mais entediante atualizá-lo.
E se você tiver que escrever um novo código agora no padrão C ++ 03 (e não puder usar o nullptr), deverá realmente usar o NULL. Isso facilitará muito a atualização no futuro.
fonte
Eu normalmente uso 0. Não gosto de macros e não há garantia de que algum cabeçalho de terceiros que você está usando não redefina NULL para ser algo estranho.
Você pode usar um objeto nullptr como proposto por Scott Meyers e outros até que o C ++ obtenha uma palavra-chave nullptr:
Google "nullptr" para mais informações.
fonte
(void*)0
se estiver sendo compilado como código C) está apenas pedindo problemas e não deve ser usada.NULL
mais(type *)0
é pesquisabilidade, parece-me. Caso contrário, parece ofuscação desnecessária se não fosse um idioma C. Pessoalmente, acho que o idioma de se espalharNULL
por todo o lugar merece morrer.NULL
é macro inútil na minha opinião. Navalha de Occam tem algum trabalho a fazer aqui ...Certa vez, trabalhei em uma máquina em que 0 era um endereço válido e NULL foi definido como um valor octal especial. Nessa máquina (0! = NULL), código como
não funcionaria como você espera. Você teve que escrever
Embora eu acredite que a maioria dos compiladores defina NULL como 0 atualmente, ainda me lembro da lição daqueles anos atrás: NULL não é necessariamente 0.
fonte
Eu acho que o padrão garante que NULL == 0, então você pode fazer qualquer um. Prefiro NULL porque documenta sua intenção.
fonte
foo.bar_ptr = (Bar *) 0
expressa a intenção muito mais clara do quefoo.bar_ptr = NULL
. Esse hábito também capacita o compilador a detectar erros de concepção errada para você. Para mim,foo.bar_ptr = 0
expressa a intenção e o uso,NULL
se eu sei quefoo.bar_ptr
é um ponteiro.Usar 0 ou NULL terá o mesmo efeito.
No entanto, isso não significa que ambas sejam boas práticas de programação. Dado que não há diferença no desempenho, a escolha de uma opção com reconhecimento de baixo nível sobre uma alternativa agnóstica / abstrata é uma prática ruim de programação. Ajude os leitores do seu código a entender seu processo de pensamento .
NULL, 0, 0,0, '\ 0', 0x00 e tudo o mais são traduzidos para a mesma coisa, mas são entidades lógicas diferentes no seu programa. Eles devem ser usados como tal. NULL é um ponteiro, 0 é quantidade, 0x0 é um valor cujos bits são interessantes etc. Você não atribuiria '\ 0' a um ponteiro, seja ele compilado ou não.
Sei que algumas comunidades incentivam a demonstrar conhecimento profundo de um ambiente, quebrando os contratos do ambiente. Programadores responsáveis, no entanto, criam código sustentável e mantêm essas práticas fora de seu código.
fonte
Estranho, ninguém, incluindo Stroustroup mencionou isso. Ao falar muito sobre padrões e estética, ninguém percebeu que é perigoso usá-lo
0
emNULL
seu lugar, por exemplo, na lista de argumentos variáveis na arquitetura em quesizeof(int) != sizeof(void*)
. Como Stroustroup, prefiro0
por razões estéticas, mas é preciso ter cuidado para não usá-lo onde seu tipo possa ser ambíguo.fonte
0
desde que você especificar que0
você quer dizer - por exemplo(int *)0
,(char *)0
,(const char *)0
ou(void *)0
ou(unsigned long long) 0
ou qualquer outra coisa. Na minha opinião, isso expressa a intenção muito mais clara do queNULL
.NULL
significa.(void *)
quando eu pudesse usar o tipo exato. De propósito, dei um exemplo (geralmente) de número inteiro de 64 bits na lista porque é análogo ao caso do ponteiro. Além disso, se minha lembrança de que C ++ mais antigo definiuNULL
como0
precisa (faz anos desde que eu programei em C ++), não testemunhamos nenhuma melhoria na correção do programa. Felizmente, o padrão C ++ mais recente fornecenullptr
palavras-chave, para que possamos nos livrar dessaNULL
feiúra e de toda a controvérsia ao escrever C ++ mais recente.(void*)
foi abstraídoNULL
. E,NULL
na verdade, expressa claramente a intenção na maioria das vezes. E acho que sua lembrança está errada. Não tenho certeza sobre os padrões, mas, na prática, acredito que tenha sido(void*)0
. E sim,nullptr
é um bom prettificador, embora seja o mesmoNULL
- especificar ponteiro nulo sem especificar o tipo.nullptr
traz a mesma mensagem queNULL
, era apenas para expressar a intenção que você mencionou no começo. (PréNULL
- processamento degcc
rendimentos modernos__null
, seja o que for).Eu tento evitar toda a pergunta usando referências C ++ sempre que possível. Ao invés de
você pode frequentemente escrever
Claro, isso nem sempre funciona; mas ponteiros nulos podem ser usados em excesso.
fonte
Estou com o Stroustrup neste :-) Como o NULL não faz parte do idioma, prefiro usar 0.
fonte
Preferência principalmente pessoal, embora se possa argumentar que NULL torna bastante óbvio que o objeto é um ponteiro que atualmente não aponta para nada, por exemplo
IIRC, o padrão não exige que NULL seja 0, portanto, usar o que estiver definido em <stddef.h> provavelmente é o melhor para o seu compilador.
Outra faceta do argumento é se você deve usar comparações lógicas (conversão implícita para bool) ou verificação de explicitação contra NULL, mas isso também se resume à legibilidade.
fonte
Prefiro usar NULL, pois deixa claro que sua intenção é que o valor represente um ponteiro e não um valor aritmético. O fato de ser uma macro é lamentável, mas, uma vez que é tão amplamente arraigado, há pouco perigo (a menos que alguém faça algo realmente tímido). Eu gostaria que fosse uma palavra-chave desde o início, mas o que você pode fazer?
Dito isto, não tenho nenhum problema em usar ponteiros como valores de verdade em si mesmos. Assim como no NULL, é um idioma arraigado.
O C ++ 09 adicionará a construção nullptr que acho que está muito atrasada.
fonte
Eu sempre uso 0. Não por qualquer motivo real, apenas porque quando eu estava aprendendo C ++, eu li algo que recomendava o uso de 0 e sempre fiz dessa maneira. Em teoria, poderia haver um problema de confusão na legibilidade, mas, na prática, nunca encontrei esse problema em milhares de horas-homem e milhões de linhas de código. Como Stroustrup diz, é realmente apenas uma questão estética pessoal até que o padrão se torne nulo.
fonte
Alguém me disse uma vez ... Vou redefinir NULL para 69. Desde então, não o uso: P
Isso torna seu código bastante vulnerável.
Editar:
Nem tudo no padrão é perfeito. A macro NULL é uma constante de ponteiro nulo C ++ definida pela implementação que não é totalmente compatível com a macro C NULL, que além do tipo oculto implícito a converte em uma ferramenta inútil e propensa a erros.
NULL não se comporta como um ponteiro nulo, mas como um literal de O / OL.
Diga-me que o próximo exemplo não é confuso:
É por tudo isso, no novo padrão aparece std :: nullptr_t
Se você não quiser esperar pelo novo padrão e quiser usar um nullptr, use pelo menos um decente como o proposto por Meyers (consulte o comentário jon.h).
fonte
NULL
é uma parte bem definida do padrão C ++. Permitir que as pessoas que gostam de redefinir macros padrão editem o código em seu projeto torna seu código 'vulnerável'; usandoNULL
não.Bem, eu argumento por não usar ponteiros 0 ou NULL, sempre que possível.
Usá-los mais cedo ou mais tarde levará a falhas de segmentação no seu código. Na minha experiência, isso e ponteiros em gereral é uma das maiores fontes de bugs em C ++
Além disso, leva a instruções "if-not-null" em todo o seu código. Muito melhor se você puder confiar sempre em um estado válido.
Quase sempre há uma alternativa melhor.
fonte
0
) é útil para depuração. Muito melhor do que desreferenciar o lixo aleatório e obter quem sabe qual resultado.Definir um ponteiro para 0 simplesmente não é tão claro. Especialmente se você vir uma linguagem diferente de C ++. Isso inclui C e Javascript.
Recentemente delt com algum código como este:
virtual void DrawTo(BITMAP *buffer) =0;
pela função virtual pura pela primeira vez. Eu pensei que fosse algum jiberjash mágico por uma semana. Quando percebi que estava basicamente configurando o ponteiro de função para a
null
(como funções virtuais são apenas ponteiros de função na maioria dos casos para C ++), me chutei.virtual void DrawTo(BITMAP *buffer) =null;
teria sido menos confuso do que aquela conversa sem espaçamento adequado para os meus novos olhos. Na verdade, estou me perguntando por que o C ++ não emprega letras minúsculas,
null
assim como emprega letras minúsculas falsas e verdadeiras agora.fonte