2011-07-21 25 views
15

Si usted tiene un objeto como NSString * someString, ¿cuál es la diferencia, si la hay, entre! == vs nula en Objective-C

if (!someString) 

vs

if (someString == nil) 

Gracias!

Respuesta

23

La primera sintaxis que se utiliza:

if (!someString) 

explota una especie de "ambigüedad" de C se deriva del hecho de que la norma original de C carecía de un tipo lógico adecuado. Por lo tanto, cualquier valor entero que equivalga a 0 se interpretó como "falso", y cualquier valor entero diferente de "0" se tomó como "verdadero". Por lo tanto, el significado de ! se define de acuerdo con esta convención y las versiones actuales del estándar C han conservado la definición original de compatibilidad.

En su caso específico, someString es un puntero, por lo que se convierte primero en un número entero, entonces ! someString se interpreta como un valor bool de true cuando someString puntos en la ubicación 0x000000, de lo contrario evals a "verdadero".

Esto está muy bien en la mayoría de condiciones (que diría siempre), pero en teoría, NULL/nilcould be different from 0x000000 bajo ciertas compiladores, por lo que (en teoría misma) que sería mejor utilizar la segunda sintaxis, que es más explícito:

if (someString == nil) 

es de todas formas más legible y desde someString no es un número entero (en lugar de un puntero), la OMI, la mejor práctica en general.

EDIT: acerca de la definición de NULL ...

Ya sea el estándar C define NULL sea 0 es un tema interesante para mí ...

Según C99 standard, sección 7.17, "definiciones comunes":

NULL [que] se expande a una constante de puntero nulo definido por la implementación;

Así, NULL se define en stddef.h a un puntero nulo definido por la implementación constante ... El mismo documento en la página 47 estados:

Un entero expresión constante con el valor 0, o una expresión tal fundido para escribir void *, que se llama un constant.55 puntero null) Si una constante puntero nulo se convierte en un tipo de puntero, el puntero resultante, llamado un puntero nulo, está garantizado para comparar desigual a un puntero a cualquier objeto o función.

Por lo tanto, la constante de puntero nulo (que es (void*)0) puede ser convertidos a un puntero nulo y esto está garantizado para comparar desigual a un puntero a cualquier objeto o función.

lo tanto, creo que, básicamente, depende de si la aplicación decide que el resultado de la conversión de un puntero nulo constante a un puntero nulo produce un puntero, que convierte de nuevo en un entero da 0. No está claro que un puntero nulo interpretado como un entero igual a 0.

yo diría que la norma realmente tratar de hacer cumplir el puntero nulo es 0, pero deja la puerta abierta a systems where the null pointer was not 0.

+2

Di +1, pero no hay ambigüedad en C sobre la idea de un valor booleano, simplemente no existe. – Perception

+3

NULL se define como '0' o' (void *) 0' por el estándar C. Incluso si el patrón de bits subyacente utilizado para el valor del puntero nulo es diferente, no cambia el hecho de que la constante del puntero nulo en C se representa como '0' o' (void *) 0'. – dreamlax

+0

@Perception: lo hace en C99. Echa un vistazo a '_Bool'. – JAB

2

En su caso significa la misma cosa. Cualquier puntero que no apunte a nil devolverá YES (verdadero).

Normalmente, el operador de signo de exclamación niega un valor BOOL.

8

Para la mayoría de los punteros, son equivalentes, aunque la mayoría de los programadores que conozco prefieren la primera, ya que es más concisa.

Para los símbolos débilmente vinculados, el primero resuelve el símbolo (y causará un bloqueo si falta) mientras que una comparación explícita contra nil o NULL no lo hará.

0

! es un operador de negación. Si su objeto no está asignado, obtendrá el mismo resultado de una tabla de verdad como lo haría con una operación == nil.

Pero,! generalmente se usa más para operaciones booleanas.

if(!isFalse) { 
    //if isFalse == NO, then this operation evaluates to YES (true) 
    [self doStuff]; 
} 

Cuando se utiliza ! en un objeto como !something sólo chequea para ver si el puntero está apuntando a nil, si no es así, devuelve cierto, y si la declaración de incendios.

2

Si se refiere a poner a prueba la condición "foo es nulo" que diga que: foo == nil.

Si se refiere a poner a prueba un valor booleano de la falsedad, !foo está bien, pero personalmente creo que un poco de signo de exclamación flaco es fácil pasar por alto, por lo que prefieren foo == NO.

escribir buen código se trata de transmitir claramente su intención de no sólo para el compilador, pero al siguiente programador que viene (posiblemente un futuro). En ambos casos, cuanto más explícito sea sobre lo que intenta hacer, mejor.

Todo eso aparte, ! y ==nil tienen el mismo efecto en todos los casos que se me ocurre.

3

El operador de prefijo bang, exclamation, ! en C es un lógico no. Al menos, es una versión de eso. Si se miraba a un no es lógica típica mesa de la verdad que se vería algo como esto:

Input  Result 
    1   0 
    0   1 

Sin embargo, en C, el operador lógico hace algo más a esto:

Input  Result 
non-zero  0 
    0   1 

Así que si tenemos en cuenta que tanto NULL y cero en Objective-C evalúan a 0, usted sabe que el operador lógico no aplicado a ellos dará como resultado un 1.

Ahora, considere el igualdad== operador. Compara el valor de dos elementos y devuelve 1 si son iguales, 0 si no lo son. Si asignó sus resultados a una tabla de verdad, se vería exactamente como los resultados de la lógica no.

En los programas C y Objective-C, la condicionalidad está realmente determinada por los int, en oposición a los booleanos reales. Esto se debe a que no hay tal cosa como un tipo de datos booleano en C. Así que escribir algo como esto funciona perfectamente bien en C:

if(5) printf("hello\n"); // prints hello 

y, además

if(2029) printf("hello\n"); // also prints hello 

Básicamente, cualquier no- int cero se evaluará como 'verdadero' en C. se combina eso con las tablas de verdad de la negación lógica y la igualdad, y se da cuenta rápidamente de que:

(! someString) and (someString == nil) 

son para todos los intentos Identificación entical!

Entonces, la siguiente pregunta lógica es, ¿por qué preferir una forma sobre otra? Desde una pura C mirador que sería sobre todo un punto de estilo, pero la mayoría (bueno) los desarrolladores elegiría la prueba de igualdad para una serie de razones:

  1. Está más cerca de lo que está tratando de expresar en código . Usted es tratando de verificar si la variable someString es nula.
  2. Es más portátil. Los lenguajes como Java tienen un tipo booleano real. No se puede usar la notación bang en sus variables o su definición NULL . El uso de la igualdad cuando sea necesario facilita el acceso al puerto C a dichos idiomas más adelante.
  3. Apple puede cambiar la definición de nil. Ok, no, no lo harán! Pero ¡nunca está de más estar seguro!
+0

"cualquier int no diferente a cero se evaluará como 'verdadero' en C" ¿Podría ser más específico al explicar cómo se evalúan las expresiones lógicas a (int) 0 o (int) 1? Diga, [si (apuntador) ...], el puntero se convierte primero en int [(int) puntero] y luego [si ((int) puntero! = 0)] evalúa a (int) 1. ¿Podría ser así que el puntero es de 64 bits mientras que int es de 32 bits y, cuando se convierte en int, los bytes más altos se truncan (if (0xffffffff00000000) => if ((int) 0x00000000))? Estaré feliz de ver dónde podría estar equivocado. –