Eu já vi definições em C
#define TRUE (1==1)
#define FALSE (!TRUE)
Isso é necessário? Qual é o benefício de simplesmente definir TRUE como 1 e FALSE como 0?
Eu já vi definições em C
#define TRUE (1==1)
#define FALSE (!TRUE)
Isso é necessário? Qual é o benefício de simplesmente definir TRUE como 1 e FALSE como 0?
Respostas:
Essa abordagem usará o boolean
tipo real (e resolverá para true
e false
) se o compilador suportar. (especificamente, C ++)
No entanto, seria melhor verificar se C ++ está em uso (via __cplusplus
macro) e realmente usar true
e false
.
Em um compilador C, isso é equivalente a 0
e 1
.
(observe que remover os parênteses quebrará isso devido à ordem das operações)
1==1
é um int
. (veja stackoverflow.com/questions/7687403/... .)
boolean
tipo?
true
ou false
.
#define TRUE true
e #define FALSE false
sempre que __cplusplus
for definido.
A resposta é portabilidade. Os valores numéricos de TRUE
e FALSE
não são importantes. O que é importante é que uma declaração como if (1 < 2)
avalia como if (TRUE)
e uma declaração como if (1 > 2)
avaliada como if (FALSE)
.
Concedido, em C, (1 < 2)
avalia 1
e (1 > 2)
avalia 0
, portanto, como outros já disseram, não há diferença prática no que diz respeito ao compilador. Mas, ao permitir que o compilador defina TRUE
e de FALSE
acordo com suas próprias regras, você está explicitando seus significados aos programadores e garantindo consistência dentro do programa e de qualquer outra biblioteca (assumindo que a outra biblioteca siga os padrões C ... ser surpreendido).
Alguma história
Alguns BASICs definidos FALSE
como 0
e TRUE
como -1
. Como muitas linguagens modernas, eles interpretaram qualquer valor diferente de zero como TRUE
, mas avaliaram expressões booleanas que eram verdadeiras como -1
. Sua NOT
operação foi implementada adicionando 1 e invertendo o sinal, porque era eficiente fazê-lo dessa maneira. Então 'NOT x' se tornou -(x+1)
. Um efeito colateral disso é que um valor como 5
avalia para TRUE
, mas NOT 5
avalia para -6
, o que também é TRUE
! Encontrar esse tipo de bug não é divertido.
Práticas recomendadas
Dadas as regras de fato em que zero é interpretado como FALSE
e qualquer valor diferente de zero é interpretado como TRUE
, você nuncaTRUE
FALSE
deve comparar expressões de aparência booleana com ou . Exemplos:
if (thisValue == FALSE) // Don't do this!
if (thatValue == TRUE) // Or this!
if (otherValue != TRUE) // Whatever you do, don't do this!
Por quê? Porque muitos programadores usam o atalho para tratar int
s como bool
s. Eles não são os mesmos, mas os compiladores geralmente permitem. Por exemplo, é perfeitamente legal escrever
if (strcmp(yourString, myString) == TRUE) // Wrong!!!
Que aparência legítimos, e o compilador terá todo o prazer aceitá-lo, mas ele provavelmente não faz o que você gostaria. Isso porque o valor de retorno de strcmp()
é
0 se yourString == myString
<0 se yourString < myString
> 0 seyourString > myString
Portanto, a linha acima retorna TRUE
apenas quando yourString > myString
.
A maneira correta de fazer isso é
// Valid, but still treats int as bool.
if (strcmp(yourString, myString))
ou
// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)
Similarmente:
if (someBoolValue == FALSE) // Redundant.
if (!someBoolValue) // Better.
return (x > 0) ? TRUE : FALSE; // You're fired.
return (x > 0); // Simpler, clearer, correct.
if (ptr == NULL) // Perfect: compares pointers.
if (!ptr) // Sleazy, but short and valid.
if (ptr == FALSE) // Whatisthisidonteven.
Você encontrará frequentemente alguns desses "exemplos ruins" no código de produção, e muitos programadores experientes juram por eles: eles funcionam, alguns são mais curtos que suas alternativas corretas (pedanticamente?) E os idiomas são quase universalmente reconhecidos. Mas considere: as versões "certas" não são menos eficientes, são garantidas para serem portáteis, elas passam pelos linters mais rígidos e até mesmo os novos programadores as entendem.
Isso não vale a pena?
(1==1)
não é mais portátil do que 1
. As regras do próprio compilador são as da linguagem C, que é clara e inequívoca sobre a semântica da igualdade e dos operadores relacionais. Eu nunca vi um compilador errar essas coisas.
strcmp
sabe-se que o valor retornado por é menor que, igual ou maior que 0. Não é garantido que seja -1, 0 ou 1 e existem plataformas em estado selvagem que não retornam esses valores para ganhar velocidade de implementação. Então, se strcmp(a, b) == TRUE
, em seguida, a > b
mas inversa implicação não pôde prender.
(1==1)
e 1
são expressões constantes do tipo int
com o valor 1. Elas são semanticamente idênticas. Suponho que você possa escrever um código que atenda a leitores que não sabem disso, mas onde termina?
O (1 == 1)
truque é útil para definir TRUE
de uma maneira que seja transparente para C, mas que ofereça melhor digitação em C ++. O mesmo código pode ser interpretado como C ou C ++ se você estiver escrevendo em um dialeto chamado "Clean C" (que é compilado como C ou C ++) ou se estiver gravando arquivos de cabeçalho de API que possam ser usados por programadores de C ou C ++.
Nas unidades de tradução C, 1 == 1
tem exatamente o mesmo significado que 1
; e 1 == 0
tem o mesmo significado que 0
. No entanto, no C ++ unidades de tradução, 1 == 1
tem tipo bool
. Portanto, a TRUE
macro definida dessa maneira se integra melhor ao C ++.
Um exemplo de como ele se integra melhor é que, por exemplo, se a função foo
tiver sobrecargas para int
e para bool
, então foo(TRUE)
ela escolherá a bool
sobrecarga. Se TRUE
for apenas definido como 1
, não funcionará bem no C ++. foo(TRUE)
vai querer a int
sobrecarga.
Claro, C99 introduzida bool
, true
e false
e estes podem ser usados em arquivos de cabeçalho que o trabalho com C99 e com C.
Contudo:
TRUE
e FALSE
como (0==0)
e (1==0)
antecede C99.Se você estiver trabalhando em um projeto misto de C e C ++ e não quiser o C99, defina as letras minúsculas e true
, em vez disso.false
bool
#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif
Dito isto, o 0==0
truque foi (é?) Usado por alguns programadores, mesmo em código que nunca teve a intenção de interoperar com o C ++ de forma alguma. Isso não compra nada e sugere que o programador tem um mal-entendido de como os booleanos funcionam em C.
Caso a explicação do C ++ não esteja clara, aqui está um programa de teste:
#include <cstdio>
void foo(bool x)
{
std::puts("bool");
}
void foo(int x)
{
std::puts("int");
}
int main()
{
foo(1 == 1);
foo(1);
return 0;
}
A saída:
bool
int
Quanto à pergunta dos comentários de como as funções C ++ sobrecarregadas são relevantes para a programação mista de C e C ++. Isso apenas ilustra uma diferença de tipo. Um motivo válido para desejar que uma true
constante seja bool
compilada como C ++ é o diagnóstico limpo. Nos níveis mais altos de aviso, um compilador C ++ pode nos alertar sobre uma conversão se passarmos um número inteiro como bool
parâmetro. Uma razão para escrever no Clean C não é apenas o fato de nosso código ser mais portátil (já que é entendido pelos compiladores C ++, não apenas pelos compiladores C), mas também podemos nos beneficiar das opiniões de diagnóstico dos compiladores C ++.
TRUE
serão diferentes em C ++.
#ifdef __cplusplus
para expressar sua intenção com muito mais clareza.
bool
e int
não importam muito na prática, pois são implicitamente conversíveis entre si (e em C, na verdade, "o mesmo" , observe as aspas , no entanto) e não há muitas situações nas quais você realmente precisa desambiguar as duas. "não muito" provavelmente foi muito pesado " , muito menos se comparado ao código que usa modelos e sobrecarga" teria sido melhor talvez.
#define TRUE (1==1)
#define FALSE (!TRUE)
é equivalente a
#define TRUE 1
#define FALSE 0
em C.
O resultado dos operadores relacionais é 0
ou 1
. 1==1
é garantido para ser avaliado 1
e !(1==1)
garantido para ser avaliado 0
.
Não há absolutamente nenhuma razão para usar a primeira forma. Observe que a primeira forma não é menos eficiente, pois em quase todos os compiladores uma expressão constante é avaliada no tempo de compilação e não no tempo de execução. Isso é permitido de acordo com esta regra:
(C99, 6.6p2) "Uma expressão constante pode ser avaliada durante a tradução, em vez do tempo de execução, e, portanto, pode ser usada em qualquer lugar em que uma constante possa estar."
O PC-Lint emitirá uma mensagem (506, valor constante booleano) se você não usar um literal para TRUE
e FALSE
macros:
Para C,
TRUE
deve ser definido para ser1
. No entanto, outros idiomas usam quantidades diferentes de 1, então alguns programadores acham que!0
estão jogando com segurança.
Também em C99, as stdbool.h
definições para macros booleanas true
e false
usam diretamente literais:
#define true 1
#define false 0
1==1
é garantido para ser avaliado para1
if(foo == true)
, que passará de meramente má prática a um buggy simples.
(x == TRUE)
pode ter um valor de verdade diferente de x
.
Além do C ++ (já mencionado), outro benefício é para ferramentas de análise estática. O compilador eliminará quaisquer ineficiências, mas um analisador estático pode usar seus próprios tipos abstratos para distinguir entre resultados de comparação e outros tipos inteiros; portanto, sabe implicitamente que TRUE deve ser o resultado de uma comparação e não deve ser considerado compatível. com um número inteiro.
Obviamente, C diz que eles são compatíveis, mas você pode optar por proibir o uso deliberado desse recurso para ajudar a destacar bugs - por exemplo, onde alguém pode ter se confundido &
e &&
/ ou eles confundiram sua precedência de operador.
if (boolean_var == TRUE)
por meio de expansão para a if (boolean_var == (1 == 1))
qual, graças às informações aprimoradas de tipo do (1 == 1)
nó, caiam no padrão if (<*> == <boolean_expr>)
.
A diferença prática é nenhuma. 0
é avaliado false
e 1
avaliado como true
. O fato de você usar uma expressão booleana ( 1 == 1
) ou 1
, para definir true
, não faz diferença. Ambos são avaliados para int
.
Note-se que a biblioteca padrão C proporciona um cabeçalho específico para definir booleanos: stdbool.h
.
true
é avaliado 1
e false
avaliado como 0
. C não sabe sobre tipos booleanos nativos, são apenas ints.
int
, com valor 0
ou 1
. C tem um tipo booleano real ( _Bool
com um macro bool
definido no <stdbool.h>
, mas que só foi adicionada no C99, que se não mudar a semântica dos operadores para usar o novo tipo.
_Bool
, e <stdbool.h>
tem #define bool _Bool
.
1 == 1
ser avaliado como int
. Editado.
Não sabemos o valor exato que TRUE é igual e os compiladores podem ter suas próprias definições. Então, o que você privode é usar o interno do compilador para definição. Isso nem sempre é necessário se você tiver bons hábitos de programação, mas puder evitar problemas por algum estilo de codificação ruim, por exemplo:
if ((a> b) == VERDADEIRO)
Isso pode ser um desastre se você definir manualmente TRUE como 1, enquanto o valor interno de TRUE for outro.
>
operador sempre produz 1 para verdadeiro, 0 para falso. Não há possibilidade de nenhum compilador C estar errado. Comparações de igualdade TRUE
e FALSE
estilo pobre; o acima é mais claramente escrito como if (a > b)
. Mas a idéia de que diferentes compiladores C podem tratar a verdade e o falso de maneira diferente é incorreta.
Normalmente, na linguagem de programação C, 1 é definido como verdadeiro e 0 é definido como falso. Por isso, você vê o seguinte com bastante frequência:
#define TRUE 1
#define FALSE 0
No entanto, qualquer número diferente de 0 seria avaliado como verdadeiro também em uma instrução condicional. Portanto, usando o abaixo:
#define TRUE (1==1)
#define FALSE (!TRUE)
Você pode apenas mostrar explicitamente que está tentando jogar pelo seguro, tornando falso igual ao que não é verdadeiro.
#define TRUE (’/’/’/’)
:;#define FALSE (’-’-’-’)
(extraído de coding-guidelines.com/cbook/cbook1_1.pdf página 871)