2010-08-20 11 views
8

Las sentencias condicionales Do C siempre devuelven [1 o 0], o devuelven [0 o 'algo diferente de cero']. Lo pregunto porque:¿Un condicional C siempre devolverá 1 o 0?

seudo código -

foo (dirección, shouldSend):
registro >> = 1
registro < < = 1 // para borrar bits en la primera posición
registro | = shouldSend // para indicar si se debe enviar o no

El problema se produce si alguien ingresa un valor de shouldSend de verdadero mayor que uno (como solo 0 es falso y todo lo demás es cierto, técnicamente esto es válido). ya que estoy directamente en el valor de verdad de shouldEnviar con el registro, ¡mejor no decir 0xFF! Ya tengo una solución, entonces la pregunta es más por curiosidad. Me pregunto aunque si:

foo (dirección, shouldSend):
registro >> = 1
registro < < = 1 // para borrar bits en la primera posición
registro | = (shouldSend> 0) // para indicar si debe enviar o no

resuelve el problema? Creo que ahora el problema de un 0xFF (o en general, algo mayor que 1) pasado es enmascarado por el condicional C. pero esto solo tiene validez SI los condicionales C están garantizados para regresar [0 o 1].

ps - también me doy cuenta de que es probablemente dependiente del compilador, pero ¿qué dice el estándar ansi sobre esto?

+0

¿No debería ser (shouldSend! = 0)? Usar !! shouldSend es un truco malvado. –

Respuesta

16

estándar especifica que el resultado es siempre valor entero igual a 0 o 1

6.5.8 operadores relacionales

Cada uno de los operadores < (menor que),> (mayores de), < = (menor o igual a a), y> = (mayor o igual que) rendirá 1 si la relación especificada es verdadera y 0 si es falso.92) El resultado ha tipo int.

+0

+1, bastante sorprendente que especifique ese comportamiento. Con el tiempo solo asumo que la especificación sería más probable que diga "devuelve 0 o tirada aleatoria de los dados" – JaredPar

+0

Sí, el estándar es perfectamente claro al respecto. –

+1

Esto lleva al modismo que he visto usado desde antes de que existiera un estándar: '!! somevalue' que tiene el mismo valor de verdad, pero que ahora se garantiza que sea exactamente 0 o 1. – RBerteig

1

No importa si está especificado o no. Lo mejor es probar siempre en contra de lo falso y ser explícito acerca de sus valores iguales o iguales. Esto elimina cualquier preocupación sobre las implementaciones del compilador y es más claro y más fácil de mantener.

+0

Eso es realmente relevante, ya que podrías usa & y | operadores como operadores lógicos SIN cortocircuito. – Spidey

1

En lugar de correr a la derecha e izquierda cambiando de nuevo para borrar la LSB, me bit a bit y con 0xFE:

register = register & 0xFE; 

[editar: suponiendo registro es de 8 bits. De lo contrario, adapte el operando de la derecha según sea necesario]

Pero sí, si shouldSend es el resultado de una prueba condicional, entonces el estándar lo garantiza como 0 o 1.Si hay alguna duda sobre si shouldSend podría ser generada desde cualquier otro lugar, sería conveniente poner en el tipo de precaución que tiene, o algo así

register = register | (shouldSend ? 1 : 0); 
+1

La expresión idiomática que he visto utilizaba desde antes el estándar: '!! somevalue' que tiene el mismo valor de verdad, pero que ahora garantiza exactamente 0 o 1. – RBerteig

+0

@RBerteig: ¡Agradable! – Vicky

0

Sí. Esto está garantizado en C99. No tengo la especificación C89 a mano. Por supuesto, los implementadores de compiladores han cometido errores en ocasiones para YMMV.

C99 especifica lo siguiente en el párrafo 6 de 6.5.8 operadores relacionales:

Cada uno de los operadores < (menor que), > (mayor que), < = (menor o igual que), y > = (mayor o igual que) rendirá 1 si la relación especificada es verdadera y 0 si es falsa.

las mismas o similares cláusulas aparecen en el párrafo 3 de 6.5.9 operadores de igualdad, párrafo 3 de 6.5.13 operador lógico AND, y el párrafo 3 de 6.5.14 operador lógico OR.

+0

Esto era cierto en el K & R C original y con frecuencia dependía, por lo que los estándares tenían que seguir su ejemplo. – RBerteig

Cuestiones relacionadas