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 booleantipo real (e resolverá para truee false) se o compilador suportar. (especificamente, C ++)
No entanto, seria melhor verificar se C ++ está em uso (via __cplusplusmacro) e realmente usar truee false.
Em um compilador C, isso é equivalente a 0e 1.
(observe que remover os parênteses quebrará isso devido à ordem das operações)
1==1é um int. (veja stackoverflow.com/questions/7687403/... .)
booleantipo?
trueou false.
#define TRUE truee #define FALSE falsesempre que __cplusplusfor definido.
A resposta é portabilidade. Os valores numéricos de TRUEe FALSEnã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 1e (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 TRUEe de FALSEacordo 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 FALSEcomo 0e TRUEcomo -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 NOToperaçã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 5avalia para TRUE, mas NOT 5avalia 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 FALSEe qualquer valor diferente de zero é interpretado como TRUE, você nuncaTRUEFALSE 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 ints como bools. 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 TRUEapenas 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.
strcmpsabe-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 > bmas inversa implicação não pôde prender.
(1==1)e 1são expressões constantes do tipo intcom 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 TRUEde 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 == 1tem exatamente o mesmo significado que 1; e 1 == 0tem o mesmo significado que 0. No entanto, no C ++ unidades de tradução, 1 == 1tem tipo bool. Portanto, a TRUEmacro definida dessa maneira se integra melhor ao C ++.
Um exemplo de como ele se integra melhor é que, por exemplo, se a função footiver sobrecargas para inte para bool, então foo(TRUE)ela escolherá a boolsobrecarga. Se TRUEfor apenas definido como 1, não funcionará bem no C ++. foo(TRUE)vai querer a intsobrecarga.
Claro, C99 introduzida bool, truee falsee estes podem ser usados em arquivos de cabeçalho que o trabalho com C99 e com C.
Contudo:
TRUEe FALSEcomo (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.falsebool
#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif
Dito isto, o 0==0truque 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 trueconstante seja boolcompilada 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 boolparâ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 ++.
TRUEserão diferentes em C ++.
#ifdef __cpluspluspara expressar sua intenção com muito mais clareza.
boole intnã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 é 0ou 1. 1==1é garantido para ser avaliado 1e !(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 TRUEe FALSEmacros:
Para C,
TRUEdeve ser definido para ser1. No entanto, outros idiomas usam quantidades diferentes de 1, então alguns programadores acham que!0estão jogando com segurança.
Também em C99, as stdbool.hdefinições para macros booleanas truee 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 falsee 1avaliado 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 1e falseavaliado como 0. C não sabe sobre tipos booleanos nativos, são apenas ints.
int, com valor 0ou 1. C tem um tipo booleano real ( _Boolcom um macro booldefinido 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 == 1ser 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 TRUEe FALSEestilo 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)