¿Qué es la función "afirmar"?

262

He estado estudiando tutoriales de OpenCV y encontré la assertfunción; ¿Qué hace?

eomer
fuente
20
Observe la nota de man afirmar: "afirmar () se implementa como una macro; si la expresión probada tiene efectos secundarios, el comportamiento del programa será diferente dependiendo de si se define NDEBUG. Esto puede crear Heisenbugs que desaparecen cuando se activa la depuración ".
Johannes Schaub - litb
35
@ S.Lott ahora, las personas que buscan en Google encontrarán esta página como uno de los mejores resultados de búsqueda, proporcionando una buena respuesta revisada por pares a su pregunta y promoviendo Stack Overflow al mismo tiempo, ¡así que es un +1 de mi parte!
Matt Grum
66
Es un -1 de mi parte. El primer resultado de búsqueda debe ser la documentación que el OP debería haber consultado en primer lugar.
Carreras de ligereza en órbita
9
@LightnessRacesinOrbit. Llámame perezoso, pero prefiero usar las excelentes lecturas condensadas, resumidas y explicadas de la documentación que proporcionan los usuarios expertos de SO como tú. Mi sincero agradecimiento :)
Tyson Hilmer

Respuestas:

298

assertfinalizará el programa (generalmente con un mensaje que cita la declaración de aserción) si su argumento resulta ser falso. Se usa comúnmente durante la depuración para hacer que el programa falle más obviamente si ocurre una condición inesperada.

Por ejemplo:

assert(length >= 0);  // die if length is negative.

También puede agregar un mensaje más informativo para que se muestre si falla así:

assert(length >= 0 && "Whoops, length can't possibly be negative! (didn't we just check 10 lines ago?) Tell jsmith");

O de esta manera:

assert(("Length can't possibly be negative! Tell jsmith", length >= 0));

Cuando realiza una compilación de lanzamiento (sin depuración), también puede eliminar la sobrecarga de las assertdeclaraciones de evaluación definiendo la NDEBUGmacro, generalmente con un modificador de compilación. El corolario de esto es que su programa nunca debe confiar en la ejecución de la macro de aserción.

// BAD
assert(x++);

// GOOD
assert(x);    
x++;

// Watch out! Depends on the function:
assert(foo());

// Here's a safer way:
int ret = foo();
assert(ret);

A partir de la combinación del programa que llama a abort () y no se garantiza que haga nada, las afirmaciones solo deben usarse para probar cosas que el desarrollador ha asumido en lugar de, por ejemplo, que el usuario ingrese un número en lugar de una letra (que debería ser manejado por otros medios).

bdonlan
fuente
49
"por lo assertgeneral genera una excepción" - en C ++ no genera "excepción" que llama abortar ... es un poco diferente.
Artyom
55
No creo que esta respuesta sea sobre los mismos lenguajes que la pregunta está etiquetada (C y C ++). En C y C ++, afirmar no genera una excepción, tiene paréntesis alrededor de su argumento y el #personaje no introduce un comentario.
Steve Jessop
Estas son sus opciones: haga la respuesta community-wiki y edite su pregunta eliminando las cosas viejas, pidiéndoles a otros que coloquen la información correcta. De esa manera, los votos negativos no afectarán a su representante, y las personas pueden mejorar la respuesta.
Johannes Schaub - litb
2
longitud> = 0 también resultará falso si la longitud es NaN
Andreas
1
Actualmente, en VS 2015, la afirmación con un mensaje de error no funcionará porque está fuera de servicio. Debería serassert("error message", expression)
Dooskington
102

La aserción comunicado equipo es análoga a la declaración Tras confirmar que en Inglés.

Blake7
fuente
131
Bueno, no del todo. "Asegúrese de que la luz esté apagada" significa "verifique la luz y apáguela si está encendida", no "vea si la luz está apagada y si no, explote". Yo diría que "doble verificación" es una traducción más cercana.
Luke Maurer el
77
@Luke, eso ilustra las maravillas del idioma inglés, ya que el idioma ofrece muchas formas de decir lo mismo. Pero considere afirmar (longitud> 0). Entonces podemos traducir eso a "verificar dos veces que la longitud sea mayor que cero" o "asegurarse de que la longitud sea mayor que cero" . Aunque claramente ambas opciones funcionan, sigo prefiriendo la mía;)
Blake7
44
Bueno, pero la otra interpretación es " hacer que la longitud sea mayor que cero". Entonces hay un poco más de ambigüedad.
Luke Maurer
29
Es más análogo al verbo inglés "afirmar"
Steve Carter
De hecho, "asegurarse" podría interpretarse como "verificar, y si no está bien, cambiar".
Erik Bongers
14

Echa un vistazo a

programa de ejemplo afirmar () en C ++

Muchos compiladores ofrecen una macro afirmar (). La macro afirmar () devuelve VERDADERO si su parámetro evalúa VERDADERO y toma algún tipo de acción si evalúa FALSO. Muchos compiladores abortarán el programa en una afirmación () que falla; otros lanzarán una excepción

Una característica poderosa de la macro afirmar () es que el preprocesador lo colapsa en ningún código si DEBUG no está definido. Es de gran ayuda durante el desarrollo, y cuando se envía el producto final no hay penalización de rendimiento ni aumento en el tamaño de la versión ejecutable del programa.

P.ej

#include <stdio.h>
#include <assert.h>

void analyze (char *, int);

int main(void)
{
   char *string = "ABC";
   int length = 3;

   analyze(string, length);
   printf("The string %s is not null or empty, "
          "and has length %d \n", string, length);
}

void analyze(char *string, int length)
{
   assert(string != NULL);     /* cannot be NULL */
   assert(*string != '\0');    /* cannot be empty */
   assert(length > 0);         /* must be positive */
}

/****************  Output should be similar to  ******************
The string ABC is not null or empty, and has length 3
rahul
fuente
11
¿No debería ser "si se define NDEBUG"?
RichN
2
¿De qué tratan esos "muchos compiladores"? MSVC y GCC cumplen ambos estándares en este caso. Qué compiladores no conformes: no tienen aserción; no imprima un mensaje y aborte cuando falla una afirmación; usa DEBUG en lugar del NDEBUG apropiado?
Steve Jessop el
lmao, por supuesto, es un sitio web llamado java-samples que se equivoca tanto.
underscore_d
6

La función afirmar () puede diagnosticar errores del programa. En C, se define en <assert.h>, y en C ++ se define en <cassert>. Su prototipo es

void assert(int expression);

La expresión de argumento puede ser cualquier cosa que desee probar: una variable o cualquier expresión en C. Si expresión se evalúa como VERDADERO, afirmar () no hace nada. Si expresión se evalúa como FALSO, afirmar () muestra un mensaje de error en stderr y aborta la ejecución del programa.

¿Cómo se utiliza asir ()? Se utiliza con mayor frecuencia para rastrear errores del programa (que son distintos de los errores de compilación). Un error no impide que un programa se compile, pero hace que dé resultados incorrectos o que se ejecute incorrectamente (por ejemplo, bloqueo). Por ejemplo, un programa de análisis financiero que está escribiendo puede ocasionalmente dar respuestas incorrectas. Sospecha que el problema es causado por la tasa de interés variable que toma un valor negativo, lo que nunca debería suceder. Para verificar esto, coloque la declaración

afirmar (tasa de interés> = 0); en ubicaciones del programa donde se utiliza tasa de interés. Si la variable llega a ser negativa, la macro afirmar () lo alerta. Luego puede examinar el código relevante para localizar la causa del problema.

Para ver cómo funciona afirmar (), ejecute el programa de ejemplo a continuación . Si ingresa un valor distinto de cero, el programa muestra el valor y finaliza normalmente. Si ingresa cero, la macro afirmar () fuerza la terminación anormal del programa. El mensaje de error exacto que ve dependerá de su compilador, pero este es un ejemplo típico:

Error de aserción: x, lista de archivos 19_3.c, línea 13 Tenga en cuenta que, para que afirmar () funcione, su programa debe compilarse en modo de depuración. Consulte la documentación de su compilador para obtener información sobre cómo habilitar el modo de depuración (como se explica en un momento). Cuando luego compila la versión final en modo de lanzamiento, las macros afirmar () están deshabilitadas.

 int x;

 printf("\nEnter an integer value: ");
 scanf("%d", &x);

 assert(x >= 0);

 printf("You entered %d.\n", x);
 return(0);

Ingrese un valor entero: 10

Ingresaste 10.

Ingrese un valor entero: -1

Mensaje de error: finalización anormal del programa

Su mensaje de error puede diferir, dependiendo de su sistema y compilador, pero la idea general es la misma.

Abhishek Kaushik
fuente
Usted explicó cómo funciona su programa de muestra con afirmar. No cómo funciona la afirmación en sí misma. ¿Cómo termina el programa anormalmente? ¿Lanza algún tipo de excepción? ¿Que tipo? ¿Crea una señal especial? que señal ¿Pueden las afirmaciones ser "atrapadas" por algún tipo de mecanismo de prueba y captura de C ++?
Motti Shneor
4

Cosas como 'aumenta la excepción' y 'detiene la ejecución' podrían ser ciertas para la mayoría de los compiladores, pero no para todos. (Por cierto, ¿hay declaraciones de afirmación que realmente arrojan excepciones?)

Aquí hay un significado interesante, ligeramente diferente de aserción utilizado por c6x y otros compiladores de TI: al ver ciertas declaraciones de aserción, estos compiladores usan la información en esa declaración para realizar ciertas optimizaciones. Malvado.

Ejemplo en C:

int dot_product(short *x, short *y, short z)
{
  int sum = 0
  int i;

  assert( ( (int)(x) & 0x3 ) == 0 );
  assert( ( (int)(y) & 0x3 ) == 0 );

  for( i = 0 ; i < z ; ++i )
    sum += x[ i ] * y[ i ];
  return sum;
}

Esto le dice al compilador que las matrices están alineadas en límites de 32 bits, por lo que el compilador puede generar instrucciones específicas hechas para ese tipo de alineación.

stijn
fuente
1
Entonces, ¿qué hacen si la afirmación es falsa y no se establece NDEBUG? Si esta es la versión de afirmar de <afirmar.h>, entonces el estándar requiere que imprima un mensaje y cancele. Obviamente, el estándar no dice que no se les permita optimizar en función de la verdad de la declaración, pero para cumplir, todavía tienen que abortar si es falso.
Steve Jessop el
1
siguen el comportamiento estándar
stijn
1

C ++ 11 N3337 borrador estándar

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

19.3 Afirmaciones

1 El encabezado <cassert>, descrito en (Tabla 42), proporciona una macro para documentar las aserciones del programa C ++ y un mecanismo para deshabilitar las comprobaciones de aserciones.

2 El contenido es el mismo que el encabezado de la biblioteca estándar C <afirmar.h>.

C99 N1256 borrador estándar

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

7.2 Diagnóstico <afirmar.h>

1 El encabezado <assert.h>define la macro de aserción y se refiere a otra macro, NDEBUGque no está definida por <assert.h>. Si NDEBUGse define como un nombre de macro en el punto del archivo fuente donde se incluye <afirmar.h>, la macro de afirmación se define simplemente como

 #define assert(ignore) ((void)0)

La macro de aserción se redefine de acuerdo con el estado actual de NDEBUG cada vez que <assert.h>se incluye.

2. La macro de aserción se implementará como una macro, no como una función real. Si se suprime la definición de macro para acceder a una función real, el comportamiento no está definido.

7.2.1 Diagnóstico del programa

7.2.1.1 La macro de aserción

Sinopsis

1)

#include <assert.h>
void assert(scalar expression);

Descripción

2 La macro de aserción coloca pruebas de diagnóstico en programas; se expande a una expresión vacía. Cuando se ejecuta, si la expresión (que tendrá un tipo escalar) es falsa (es decir, se compara igual a 0), la macro de aserción escribe información sobre la llamada particular que falló (incluido el texto del argumento, el nombre del archivo de origen, el número de línea de origen, y el nombre de la función de cerramiento - este último son, respectivamente, los valores de las macros de pre-procesamiento __FILE__y __LINE__y del identificador __func__) en el flujo de error estándar en un formato definido por la implementación. 165) Luego llama a la función abortar.

Devoluciones

3 La macro de aserción no devuelve ningún valor.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
1

Hay tres razones principales para utilizar la función afirmar () sobre la normal if if y printf

  1. La función afirmar () se usa principalmente en la fase de depuración, es tedioso escribir, si no, con una instrucción printf cada vez que desee probar una condición que podría no llegar al código final.

  2. En implementaciones de software grandes, la aserción es muy útil donde puede hacer que el compilador ignore las declaraciones de aserción utilizando la macro NDEBUG definida antes de vincular el archivo de encabezado para la función aserción ().

  3. afirmar () es útil cuando está diseñando una función o algún código y desea hacerse una idea de los límites que el código funcionará y no funcionará y finalmente incluirá un if if para evaluarlo básicamente jugando con suposiciones.

Nnaik
fuente
0

Es una función que detendrá la ejecución del programa si el valor que ha evaluado es falso. Por lo general, está rodeado por una macro para que no se compile en el binario resultante cuando se compila con la configuración de lanzamiento.

Está diseñado para usarse para probar las suposiciones que ha hecho. Por ejemplo:

void strcpy(char* dest, char* src){
    //pointers shouldn't be null
    assert(dest!=null);
    assert(src!=null);

    //copy string
    while(*dest++ = *src++);
}

Lo ideal que desea es que pueda cometer un error en su programa, como llamar a una función con argumentos no válidos, y hacer clic en una afirmación antes de que falle (o no funcione como se esperaba)

Yacoby
fuente
¿Por qué no usamos if & else y agregamos información de registro?
Asad Khan el
1
Porque nunca deberías pasar un puntero nulo a strcpy. Es una de esas cosas que no deberían suceder. Si se ha pasado un puntero nulo, indica que algo en un nivel superior se ha estropeado. En el mejor de los casos, tendrá que bloquear el programa más allá del problema debido a valores de datos inesperados (ya sea que destino sea incorrecto o nulo).
Yacoby el
-5

Además, puede usarlo para verificar si la asignación dinámica fue exitosa.

Ejemplo de código:

int ** p;
p = new int * [5];      // Dynamic array (size 5) of pointers to int
for (int i = 0; i < 5; ++i) {
    p[i] = new int[3]; // Each i(ptr) is now pointing to a dynamic
                       // array (size 3) of actual int values
}

assert (p);            // Check the dynamic allocation.

Similar a:

if (p == NULL) {
    cout << "dynamic allocation failed" << endl;
    exit(1);
}
Sadikov
fuente
3
No. newlanza una excepción en la falla de asignación a menos que especifique nothrow(que no hizo aquí). Además, su formato es extraño y exites malo.
Carreras de ligereza en órbita
Sí, tiene usted razón. Olvidé agregar no. Me encantaría ver cómo usará en lugar de salir
Sadikov
1
@Sadikov Cualquier otra persona manejaría una condición de error de este tipo utilizando un código que no se elimina por completo cuando se construye en modo de liberación , dejando a sus usuarios sin protección y a merced de un comportamiento indefinido si una condición previa no se cumple y, gracias a esto, es nunca comprobado y atrapado . assert()es solo para depurar y eliminar cosas que nunca, nunca, nunca sucederán, mucho antes de que se realice una versión de lanzamiento.
underscore_d