En una revisión de código reciente, un contribuyente está tratando de exigir que todas las NULL
verificaciones en los punteros se realicen de la siguiente manera:
int * some_ptr;
// ...
if (some_ptr == NULL)
{
// Handle null-pointer error
}
else
{
// Proceed
}
en vez de
int * some_ptr;
// ...
if (some_ptr)
{
// Proceed
}
else
{
// Handle null-pointer error
}
Estoy de acuerdo en que su manera es un poco más clara en el sentido de que está diciendo explícitamente "Asegúrese de que este puntero no sea NULL", pero lo contrarrestaría diciendo que cualquiera que esté trabajando en este código entendería que usar una variable de puntero en un if
afirmación está implícita comprobando NULL
. También siento que el segundo método tiene una menor posibilidad de introducir un error del tipo:
if (some_ptr = NULL)
lo cual es un dolor absoluto para encontrar y depurar.
¿Qué camino prefieres y por qué?
c++
c
if-statement
null
coding-style
Bryan Marble
fuente
fuente
Respuestas:
En mi experiencia, se prefieren las pruebas de la forma
if (ptr)
oif (!ptr)
. No dependen de la definición del símboloNULL
. No exponen la oportunidad de la asignación accidental. Y son claros y concisos.Editar: como SoapBox señala en un comentario, son compatibles con las clases de C ++, como los
auto_ptr
objetos que actúan como punteros y que proporcionan una conversiónbool
para habilitar exactamente este idioma. Para estos objetos, una comparación explícitaNULL
tendría que invocar una conversión a puntero que puede tener otros efectos secundarios semánticos o ser más costoso que la simple verificación de existencia quebool
implica la conversión.Prefiero el código que dice lo que significa sin texto innecesario.
if (ptr != NULL)
tiene el mismo significadoif (ptr)
pero a costa de una especificidad redundante. Lo siguiente lógico es escribirif ((ptr != NULL) == TRUE)
y de esa manera se encuentra la locura. El lenguaje C es claro que un booleano probado porif
,while
o similar tiene un significado específico de un valor distinto de cero es verdadero y cero es falso. La redundancia no lo hace más claro.fuente
int y = *x; if (!x) {...}
donde el optimizador puede razonar que, dado*x
que no estaría definido six
es NULL, no debe ser NULL y, por!x
lo tanto, debe ser FALSE. La expresión no!ptr
es comportamiento indefinido. En el ejemplo, si la prueba se realizó antes de usarla , entonces el optimizador estaría equivocado al eliminar la prueba.*x
if (foo)
Es lo suficientemente claro. Úsalo.fuente
Comenzaré con esto: la consistencia es el rey, la decisión es menos importante que la consistencia en su base de código.
En C ++
NULL se define como 0 o 0L en C ++.
Si ha leído El lenguaje de programación C ++, Bjarne Stroustrup sugiere usar
0
explícitamente para evitar laNULL
macro al hacer la asignación , no estoy seguro de si hizo lo mismo con las comparaciones, ha pasado un tiempo desde que leí el libro, creo que simplemente lo hizoif(some_ptr)
sin una comparación explícita pero estoy confuso en eso.La razón de esto es que la
NULL
macro es engañosa (como lo son casi todas las macros) en realidad es0
literal, no un tipo único como su nombre lo sugiere. Evitar macros es una de las pautas generales en C ++. Por otra parte,0
parece un número entero y no lo es cuando se compara o se asigna a punteros. Personalmente, podría ir en cualquier dirección, pero por lo general omito la comparación explícita (aunque a algunas personas no les gusta esto, probablemente por eso hay un colaborador que sugiere un cambio de todos modos).Independientemente de los sentimientos personales, esta es en gran medida una elección del menor mal, ya que no hay un método correcto.
Esto es claro y un idioma común y lo prefiero, no hay posibilidad de asignar accidentalmente un valor durante la comparación y se lee claramente:
Esto está claro si sabe que
some_ptr
es un tipo de puntero, pero también puede parecer una comparación de enteros:Esto es claro, en casos comunes tiene sentido ... Pero es una abstracción permeable, en
NULL
realidad es0
literal y podría terminar siendo mal utilizado fácilmente:C ++ 0x tiene nullptr, que ahora es el método preferido ya que es explícito y preciso, solo tenga cuidado con la asignación accidental:
Hasta que pueda migrar a C ++ 0x, diría que es una pérdida de tiempo preocuparse por cuál de estos métodos utiliza, todos son insuficientes, razón por la cual se inventó nullptr (junto con problemas de programación genéricos que surgieron con el reenvío perfecto .) Lo más importante es mantener la consistencia.
C ª
C es una bestia diferente.
En C NULL se puede definir como 0 o como ((void *) 0), C99 permite la implementación de constantes de puntero nulo definidas. Por lo tanto, en realidad se reduce a la definición de implementación de NULL y tendrá que inspeccionarlo en su biblioteca estándar.
Las macros son muy comunes y, en general, se usan mucho para compensar las deficiencias en el soporte de programación genérica en el lenguaje y otras cosas también. El lenguaje es mucho más simple y la dependencia del preprocesador es más común.
Desde esta perspectiva, probablemente recomendaría usar la
NULL
definición de macro en C.fuente
0
en C ++, tiene un significado en C:(void *)0
.0
es preferible aNULL
en C ++, porque los errores de tipo pueden ser un PITA.NULL
es cero de todos modos.#define NULL ((void *)0)
delinux/stddef.h
NULL
debe ser cero.Yo uso
if (ptr)
, pero esto no vale la pena discutir por completo.Me gusta mi camino porque es conciso, aunque otros dicen
== NULL
que es más fácil de leer y más explícito. Veo de dónde vienen, solo estoy en desacuerdo, las cosas adicionales lo hacen más fácil. (Odio la macro, así que soy parcial). Depende de usted.No estoy de acuerdo con tu argumento. Si no recibe advertencias para las asignaciones de manera condicional, debe aumentar sus niveles de advertencia. Simple como eso. (Y por amor a todo lo que es bueno, no los cambie).
Tenga en cuenta que en C ++ 0x, podemos hacer
if (ptr == nullptr)
, lo que para mí se lee mejor. (Nuevamente, odio la macro. Peronullptr
es agradable.) Sinif (ptr)
embargo, todavía lo hago , solo porque es a lo que estoy acostumbrado.fuente
Francamente, no veo por qué importa. Cualquiera de los dos es bastante claro y cualquier persona con experiencia moderada en C o C ++ debería entender ambos. Un comentario, sin embargo:
Si planea reconocer el error y no continuar ejecutando la función (es decir, va a lanzar una excepción o devolver un código de error inmediatamente), debe convertirla en una cláusula de protección:
De esta manera, evita el "código de flecha".
fuente
if(!p)
es un comportamiento indefinido. Podría funcionar o no.if(!p)
no es el comportamiento indefinido, es la línea anterior. Yif(p==NULL)
tendría exactamente el mismo problema.Personalmente, siempre lo he usado
if (ptr == NULL)
porque hace que mi intención sea explícita, pero en este punto es solo un hábito.El uso
=
en lugar de==
será capturado por cualquier compilador competente con la configuración de advertencia correcta.El punto importante es elegir un estilo consistente para su grupo y atenerse a él. No importa en qué dirección vayas, eventualmente te acostumbrarás, y la pérdida de fricción cuando trabajes en el código de otras personas será bienvenida.
fuente
Solo un punto más a favor de la
foo == NULL
práctica: sifoo
es, digamos, unaint *
o unabool *
, entonces elif (foo)
cheque puede ser interpretado accidentalmente por un lector como si probara el valor del pointee, es decir, comoif (*foo)
. LaNULL
comparación aquí es un recordatorio de que estamos hablando de un puntero.Pero supongo que una buena convención de nombres hace que este argumento sea discutible.
fuente
En realidad, uso ambas variantes.
Hay situaciones en las que primero verifica la validez de un puntero, y si es NULL, simplemente regresa / sale de una función. (Sé que esto puede llevar a la discusión "si una función tiene solo un punto de salida")
La mayoría de las veces, verifica el puntero, luego hace lo que desea y luego resuelve el caso de error. El resultado puede ser el feo código x-times sangrado con múltiples if's.
fuente
goto
puede ser muy útil. Además, en muchos casos, unamalloc()
que necesitaría limpieza podría ser reemplazada por una más rápidaalloca()
. Sé que no se recomiendan, pero existen por una razón (para mí, una etiqueta bien nombradagoto
es mucho más limpia que unif/else
árbol ofuscado ).alloca
no es estándar y no es completamente seguro. Si falla, su programa simplemente explota. No hay posibilidad de recuperación, y dado que la pila es relativamente pequeña, es probable que falle. En caso de falla, es posible que golpee el montón e introduzca vulnerabilidades que comprometan los privilegios. Nunca usealloca
o vlas a menos que tenga un pequeño límite en el tamaño que se asignará (y entonces también podría usar una matriz normal).El lenguaje de programación C (K&R) le haría verificar null == ptr para evitar una asignación accidental.
fuente
if (!valid)
anteriorif (valid == 0
).Si el estilo y el formato van a ser parte de sus revisiones, debe haber una guía de estilo acordada para comparar. Si hay uno, haga lo que dice la guía de estilo. Si no hay uno, los detalles como este deben dejarse tal como están escritos. Es una pérdida de tiempo y energía, y distrae de lo que las revisiones de código realmente deberían descubrir. En serio, sin una guía de estilo, presionaría para NO cambiar un código como este por principio, incluso si no usa la convención que prefiero.
Y no es que importe, pero mi preferencia personal es
if (ptr)
. El significado es más obvio para mí que inclusoif (ptr == NULL)
.¿Quizás está tratando de decir que es mejor manejar las condiciones de error antes del camino feliz? En ese caso, todavía no estoy de acuerdo con el revisor. No sé si hay una convención aceptada para esto, pero en mi opinión, la condición más "normal" debería ser lo primero en cualquier declaración if. De esa manera, tengo que investigar menos para averiguar de qué se trata la función y cómo funciona.
La excepción a esto es si el error hace que me retire de la función, o puedo recuperarme de ella antes de continuar. En esos casos, primero manejo el error:
Al tratar la condición inusual por adelantado, puedo ocuparme de ella y luego olvidarla. Pero si no puedo volver al camino feliz manejándolo por adelantado, entonces debería ser manejado después del caso principal porque hace que el código sea más comprensible. En mi opinión.
Pero si no está en una guía de estilo, entonces es solo mi opinión, y su opinión es igual de válida. O estandarizar o no. No permita que un crítico pseudo-estandarice solo porque tiene una opinión.
fuente
Este es uno de los fundamentos de ambos lenguajes que los punteros evalúan para un tipo y valor que puede usarse como una expresión de control,
bool
en C ++ yint
en C. Simplemente utilícelo.fuente
if (foo = bar)
por accidente.Por eso prefiero
o
Sin embargo, si estuviera escribiendo un conjunto de pautas de estilo, no estaría poniendo cosas como esta, estaría poniendo cosas como:
fuente
Soy un gran fan del hecho de que C / C ++ no comprueba los tipos en las condiciones booleanas en
if
,for
ywhile
declaraciones. Siempre uso lo siguiente:incluso en enteros u otro tipo que se convierte en bool:
La codificación en este estilo es más legible y más clara para mí. Solo mi opinión personal.
Recientemente, mientras trabajaba en el microcontrolador OKI 431, noté que lo siguiente:
es más eficiente que
porque en un caso posterior el compilador tiene que comparar el valor de chx a 1. Donde chx es solo un indicador verdadero / falso.
fuente
La mayoría de los compiladores que he usado al menos advertirán sobre la
if
tarea sin más azúcar de sintaxis, por lo que no compro ese argumento. Dicho esto, he usado ambos profesionalmente y no tengo preferencia por ninguno. El== NULL
es definitivamente más claro, aunque en mi opinión.fuente