una - ¿El estándar C indica explícitamente el valor de verdad como 0 o 1?
valor de verdad de las proposiciones compuestas (7)
¿El estándar C indica explícitamente los valores de
true
detrue
yfalse
como0
y1
respectivamente?
El estándar C define
true
y
false
como macros en
stdbool.h
que se expanden a
1
y
0
respectivamente.
C11-§7.18:
Las tres macros restantes son adecuadas para su uso en
#if
directivas de preprocesamiento. Son
true
que se expande a la constante entera
1
,
false
que se expande a la constante entera
0
[...]
En cuanto a los operadores
==
y
!=
C11-§6.5.9 / 3:
Los operadores
==
(igual a) y!=
(No igual a) son análogos a los operadores relacionales, excepto por su precedencia más baja. 108) Cada uno de los operadores produce1
si la relación especificada es verdadera y0
si es falsa. El resultado tiene tipoint
. Para cualquier par de operandos, exactamente una de las relaciones es verdadera.
Sabemos que cualquier número que no sea igual a
0
se considera
true
en C, por lo que podemos escribir:
int a = 16;
while (a--)
printf("%d/n", a); // prints numbers from 15 to 0
Sin embargo, me preguntaba si verdadero / falso se define como
0
en C, así que probé el siguiente código:
printf("True = %d, False = %d/n", (0 == 0), (0 != 0)); // prints: True = 1, False = 0
¿El estándar C indica explícitamente los valores de verdad de verdadero y falso como
1
y
0
respectivamente?
Está mezclando muchas cosas diferentes: declaraciones de control, operadores y tipos booleanos. Cada uno tiene sus propias reglas.
Las declaraciones de control funcionan como, por ejemplo, la declaración
if
, C11 6.4.8.1:
En ambas formas, la primera subestimación se ejecuta si la expresión se compara desigual a 0.
while
for
etc tienen la misma regla.
Esto no tiene nada que ver con "verdadero" o "falso".
En cuanto a los operadores que supuestamente están produciendo un resultado booleano, en realidad están produciendo un
int
con valor 1 o 0. Por ejemplo, los operadores de igualdad, C11 6.5.9:
Cada uno de los operadores produce 1 si la relación especificada es verdadera y 0 si es falsa
Todo lo anterior se debe a que C no tenía un tipo booleano hasta el año 1999, e incluso cuando lo obtuvo, las reglas anteriores no se modificaron.
Entonces, a diferencia de la mayoría de los otros lenguajes de programación donde las declaraciones y los operadores producen un tipo booleano (como C ++ y Java), solo producen un
int
, con un valor cero o no cero.
Por ejemplo,
sizeof(1==1)
dará 4 en C pero 1 en C ++.
El tipo booleano real en C se llama
_Bool
y requiere un compilador moderno.
El encabezado
stdbool.h
define macros
bool
,
true
y
false
, que se expanden a
_Bool
,
1
y
0
respectivamente (para compatibilidad con C ++).
Sin embargo, se considera una buena práctica de programación tratar las declaraciones de control y los operadores como si realmente requirieran / produjeran un tipo booleano. Ciertos estándares de codificación como MISRA-C recomiendan dicha práctica. Es decir:
if(ptr == NULL)
lugar de
if(ptr)
.
if((data & mask) != 0)
lugar de
if(data & mask)
.
El objetivo de este estilo es aumentar la seguridad de los tipos con la ayuda de herramientas de análisis estático, que a su vez reduce los errores. Podría decirse que este estilo solo es significativo si utiliza analizadores estáticos. Aunque en algunos casos conduce a un código más fácil de documentar, por ejemplo
if(c == ''/0'')
Bien, la intención es clara, el código se documenta por sí mismo.
versus
if(c)
Malo.
Podría significar cualquier cosa, y tenemos que buscar el tipo de
c
para entender el código.
¿Es un número entero, un puntero o un personaje?
Esta respuesta debe analizarse un poco más de cerca.
La definición real en C ++ es que todo lo que no sea 0 se trata como verdadero. ¿Por qué es esto relevante? Debido a que C ++ no sabe qué es un número entero por cómo lo pensamos: creamos ese significado, todo lo que tiene es el caparazón y las reglas de lo que eso significa. Sin embargo, sabe qué bits son, lo que constituye un número entero.
1 como número entero se representa libremente en bits, digamos un int con signo de 8 bits como 0000 0001. Muchas veces lo que vemos visualmente es una mentira, -1 es una forma mucho más común de representarlo debido a la naturaleza firmada de ''entero''. Realmente no puedo decir verdad, ¿por qué? Porque su operación NO es 1111 1110. Ese es un problema realmente importante para un booleano. Cuando hablamos de un booleano, es solo 1 bit: es realmente simple, 0 es falso y 1 es verdadero. Todas las operaciones lógicas se consideran triviales. Es por eso que ''-1'' debe designarse como ''verdadero'' para enteros (con signo). 1111 1111 NOT''ed se convierte en 0000 0000 --- la lógica se mantiene y estamos bien. Las entradas sin signo son un poco complicadas y se usaban mucho más en el pasado, donde 1 significa verdadero porque es fácil implicar la lógica de que ''cualquier cosa que no sea 0 es verdadera''.
Esa es la explicación. Digo que la respuesta aceptada aquí es incorrecta: no hay una definición clara en la definición de C / C ++. Un booleano es un booleano, puede tratar un entero como un booleano, pero el hecho de que la salida sea un entero no dice nada acerca de la operación que se está haciendo en realidad.
Hay dos áreas del estándar que debe tener en cuenta al tratar con valores booleanos (con los cuales quiero decir valores verdaderos / falsos en lugar del tipo específico C
bool/_Bool
) en C.
El primero tiene que ver con el
resultado
de las expresiones y se puede encontrar en varias partes de
C11 6.5 Expressions
(operadores relacionales y de igualdad, por ejemplo).
La conclusión es que, cada vez que una expresión genera un valor booleano, ...
... produce 1 si la relación especificada es verdadera y 0 si es falsa. El resultado tiene el tipo int.
Entonces, sí, el resultado de cualquier expresión booleana que genere será uno para verdadero o cero para falso.
Esto coincide con lo que encontrará en
stdbool.h
donde las macros estándar
true
y
false
se definen de la misma manera.
Sin embargo, tenga en cuenta que, siguiendo el principio de robustez de "ser conservador en lo que envía, liberal en lo que acepta", la interpretación de los enteros en el contexto booleano es algo más relajada.
Nuevamente, desde varias partes de
6.5
, verá un lenguaje como:
El
||
el operador producirá 1 si alguno de sus operandos se compara desigual a 0; de lo contrario, produce 0. El resultado tiene el tipo int.
A partir de eso (y otras partes), es obvio que cero se considera falso y cualquier otro valor es verdadero.
Por otro lado, el lenguaje que especifica qué valores se usan para la generación e interpretación booleana también aparece en C99 y C89, por lo que han existido durante bastante tiempo. Incluso K&R (segunda edición de ANSI-C y la primera edición) especificó eso, con segmentos de texto como:
Expresiones relacionales como
i > j
y expresiones lógicas conectadas por&&
y||
se definen para tener el valor1
si es verdadero y0
si es falso.En la parte de prueba de
if
,while
,for
, etc., "verdadero" solo significa "distinto de cero".El operador
&&
... devuelve 1 si sus dos operandos se comparan desigualmente con cero, 0 de lo contrario.El
||
operador ... devuelve 1 si cualquiera de sus operandos se compara desigual a cero, y 0 en caso contrario.
Las macros en
stdbool.h
aparecen en C99, pero no en C89 o K&R ya que ese archivo de encabezado no existía en ese momento.
He programado en muchos idiomas. He visto verdadero ser 1 o -1 dependiendo del idioma. La lógica detrás del verdadero ser 1 era que un bit era 0 o 1. La lógica detrás del verdadero ser -1 era que el! El operador era el complemento de uno. Cambió todos los 1 a 0 y todos los 0 a 1 en un int. Entonces, para un int,! 0 = -1 y! (- 1) = 0. Esto me ha hecho tropezar lo suficiente como para que no compare algo como == verdadero, sino que lo compare como falso =. De esa manera, mi estilo de programación funciona en todos los idiomas. Entonces, mi respuesta es no preocuparme por eso, sino programar para que su código funcione correctamente de cualquier manera.
No se indica explícitamente en C11. Todas las operaciones a nivel de lenguaje devolverán 1 como verdadero (y aceptarán cualquier valor distinto de cero, incluido NaN, como verdadero).
-
Si le preocupa
_Bool
, true debe ser 1 porque el estándar solo requiere que contenga 0 y 1. (§6.2.5 / 2). -
También en
<stdbool.h>
la macrotrue
expande a1
(§7.18 / 3) -
==
,!!=
,<
,>
,<=
y>=
devolver 0 o 1 (§6.5.8 / 6, §6.5.9 / 3). -
!
,&&
y||
devuelve 0 o 1 (§6.5.3.3 / 5, §6.5.13 / 3, §6.5.14 / 3) -
defined
expande a 0 o 1 (§6.10.1 / 1)
Pero todas
las funciones estándar de la biblioteca,
por ejemplo,
islower
simplemente dicen "distinto de cero" para la verdad (por ejemplo, §7.4.1 / 1, §7.17.5.1 / 3, §7.30.2.1 / 1, §7.30.2.2.1 / 4).
§6.2.5 / 2 : Un objeto declarado como tipo
_Bool
es lo suficientemente grande como para almacenar los valores 0 y 1.§6.5.5.3 / 5 : ¡El resultado del operador de negación lógica
!
es 0 si el valor de su operando se compara desigual a 0, 1 si el valor de su operando se compara igual a 0. ...§6.5.8 / 6 : Cada uno de los operadores
<
(menor que),>
(mayor que),<=
(menor o igual que) y>=
(mayor o igual que) producirá 1 si la relación especificada es verdadero y 0 si es falso. 107) ...§6.5.9 / 3 : Los operadores
==
(igual a) y!=
(No igual a) son análogos a los operadores relacionales, excepto por su precedencia más baja.108) Cada uno de los operadores produce 1 si la relación especificada es verdadera y 0 si es falso. ...§6.5.13 / 3 : El operador
&&
producirá 1 si sus dos operandos se comparan desigualmente con 0; ...§6.5.14 / 3 : El
||
el operador producirá 1 si alguno de sus operandos se compara desigual a 0; ...§6.10.1 / 1 : ... puede contener expresiones de operador unario de la forma -
defined identifier
- o -defined ( identifier )
- que evalúan a 1 si ...§7.4.1 (Funciones de clasificación de caracteres) / 1 : Las funciones de esta subcláusula devuelven distinto de cero (verdadero) si y solo si ...
§7.18 / 3 : Las tres macros restantes son adecuadas para usar en
#if
directivas de preprocesamiento. Son -true
- que se expanden a la constante entera 1, ...§7.17.5.1 / 3 : La función genérica
atomic_is_lock_free
devuelve distinto de cero (verdadero) si y solo si las operaciones del objeto están libres de bloqueo. ...§7.30.2.1 (Funciones de clasificación de caracteres anchos) / 1 : Las funciones en esta subcláusula devuelven distinto de cero (verdadero) si y solo si ...
§7.30.2.2.1 / 4 : La función
iswctype
devuelve distinto de cero (verdadero) si y solo si ...
Sucedió debido a los operadores relacionales en su declaración
printf
.
Operador
==
y operador
!=
Como
(0 == 0)
es verdadero, da un valor
1
mientras que
(0 != 0)
no es cierto, entonces da un valor
0
.