¿Cuándo debemos usar aserciones en C?

Estoy escribiendo una función en C. Como cuestión de estilo, ¿cuándo es bueno usar aseverar en comparación con devolver un código de error? Digamos que la función está dividiendo dos números. ¿Debo afirmar que el divisor no es cero o debo devolver un código de error? Por favor, proporcione más ejemplos, si puede, para aclarar la distinción.

assert aborta el proceso, pero se convierte en un no-op cuando el progtwig se comstack con -DNDEBUG , por lo que es una herramienta de depuración bastante burda y nada más que eso. Solo debe usar assert para verificar situaciones que “no pueden suceder”, por ejemplo, que violan las condiciones invariantes o posteriores de un algoritmo, pero probablemente no para la validación de entrada (ciertamente no en bibliotecas). Cuando detecte una entrada no válida de los clientes, sea amigable y devuelva un código de error.

Un ejemplo de uso de assert podría ser: ha implementado un algoritmo de clasificación increíblemente inteligente y desea comprobar si realmente se clasifica. Dado que se supone que la función de clasificación “simplemente funciona” y, por lo tanto, no devuelve un valor, no puede agregar devoluciones de error sin cambiar la API.

 void sort(int *a, size_t n) { recursive_super_duper_sort(a, 0, n); assert(is_sorted(a, n)); } static bool is_sorted(int const *a, size_t n) { for (size_t i=0; i a[i+1]) return false; return true; } 

A largo plazo, realmente desearía un marco de prueba de unidad adecuado para este tipo de cosas en lugar de assert , pero es útil como una herramienta de depuración temporal.

Un código de error señala el comportamiento en tiempo de ejecución. Una afirmación es una herramienta de depuración que le permite al desarrollador afirmar que sus suposiciones sobre la lógica del progtwig son verdaderas.

Son dos cosas completamente diferentes con diferentes aplicaciones.

Los códigos de error son parte de su flujo de progtwig normal. Las aserciones son solo para la depuración, y si se desencadena una aserción, eso significa que su progtwig no está escrito correctamente.

En general, las afirmaciones son para el progtwigdor (es decir, usted) para encontrar errores de lógica / progtwigción antes de lanzar el progtwig a usuarios reales. Las alertas no se deben usar para detectar errores de entrada en el tiempo de ejecución; use códigos de error para estos.

Esto es realmente una cuestión de gusto. Aquí está mi opinión.

La principal regla de oro: un fallo de aserción es siempre un error en el progtwig.

Use una assert para verificar los parámetros de la función si espera que la persona que llama se asegure de que el argumento sea correcto y que desea indicar que cualquier otro comportamiento es un error en la persona que llama. La división por cero es, IMO, un muy buen ejemplo.

Use un código de error si espera que la persona que llama no pueda asegurarse de que el argumento sea correcto antes de llamar. Por ejemplo, podría ser muy costoso computacionalmente verificar los argumentos de antemano.

Nunca use una assert para verificar la entrada del usuario.

La sabiduría convencional es usar assert () para ayudar a depurar su código, para advertirle cuando algo “imposible”, algo que no debe suceder, ha sucedido. Esta “advertencia” toma la forma de salir de su progtwig.

He escuchado a Jim Coplien (defensor general de C ++ y defensor de SCRUM) abogar por dejar sus afirmaciones activas en el código desplegado. (Parece una locura, lo sé …) Esto fue específicamente para el código del servidor de alta confiabilidad. La motivación fue que es mejor fallar, duro, y dejar que otro nodo tome el control, que tolerar que su servidor se encuentre en un estado “imposible”.

(Y, por supuesto, rastrear las fallas y analizarlas. Esto significa que hay un error o una suposición incorrecta).

Primero, assert desde el se puede deshabilitar (por ejemplo, comstackndo con gcc -DNDEBUG ), y algunas veces se deshabilita para la versión “producción” de un binario.

En segundo lugar, como lo indica la página del manual de Linux,

  The purpose of this macro is to help the programmer find bugs in his program. The message "assertion failed in file foo.c, function do_bar(), line 1287" is of no help at all to a user. 

Así que afirmar debería fallar solo en situaciones de buggy. En situaciones excepcionales o de error, deberías hacer otra cosa.

Algunas herramientas (o incluso comstackdores) pueden usar assert para, por ejemplo, optimizar su código.

En su ejemplo de una función de quotient , usará assert si, dentro de todo su progtwig, está seguro de que el divisor no debe ser cero (pero entonces podría tener sentido nombrar la función de manera diferente, tal vez quotient_by_non_zero ). Si considera que podría suceder, conviértalo en un mensaje fatal, una excepción (es decir, longjmp en C), un código de error, etc.

Como C no admite excepciones, no tiene otra opción real que no sea devolver un código de error. Una falla en C assert() hace que se abort() que bombardea el proceso. Eso no es realmente comparable con el manejo de errores estándar.

Para operaciones de punto flotante puede usar NaN para indicar condiciones de error. Para operaciones de enteros, un código de error es simplemente su única opción.

Use una afirmación cuando su progtwig se encuentre con una situación que no permita continuar. Las afirmaciones son un ‘contrato’ y las uso como un ‘contrato’ con el sistema operativo y la situación ‘peligro en retraso’.

Para emular las excepciones, puede seguir utilizando GOTO ‘ERRORLABEL’ y terminar la limpieza después de ejecutar una función de limpieza.