O que é a função "afirmar"?


262

Eu estudei os tutoriais do OpenCV e me deparei com a assertfunção; O que isso faz?


20
Observe a nota do man assert: "assert () é implementado como uma macro; se a expressão testada tiver efeitos colaterais, o comportamento do programa será diferente dependendo da definição de NDEBUG. Isso pode criar Heisenbugs que desaparecem quando a depuração é ativada. . "
Johannes Schaub - litb 15/10/09


35
@ S.Lott agora as pessoas que pesquisam no google encontrarão esta página como um dos principais resultados de pesquisa, fornecendo uma boa resposta revisada por pares para suas perguntas e promovendo o Stack Overflow ao mesmo tempo, portanto é um +1 de mim!
precisa saber é o seguinte

6
É um -1 de mim. O resultado principal da pesquisa deve ser a documentação que o OP deveria ter consultado em primeiro lugar.
Lightness Races in Orbit

9
@LightnessRacesinOrbit. Me chame de preguiçoso, mas prefiro usar as excelentes leituras condensadas, resumidas e explicadas da documentação que os usuários experientes de SO, como você, fornecem. Meu sincero obrigado :)
Tyson Hilmer

Respostas:


298

assertencerrará o programa (geralmente com uma mensagem citando a declaração assert) se o argumento for falso. É comumente usado durante a depuração para fazer com que o programa falhe mais obviamente se ocorrer uma condição inesperada.

Por exemplo:

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

Você também pode adicionar uma mensagem mais informativa a ser exibida se ela falhar assim:

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

Ou então:

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

Ao fazer uma compilação de liberação (sem depuração), você também pode remover a sobrecarga das assertinstruções de avaliação definindo a NDEBUGmacro, geralmente com uma opção de compilador. O corolário disso é que seu programa nunca deve confiar na execução de macro de afirmação.

// 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 da combinação do programa que chama abort () e não tem garantia de fazer nada, as afirmações devem ser usadas apenas para testar coisas que o desenvolvedor assumiu em vez de, por exemplo, o usuário digitar um número em vez de uma letra (que deve ser manipulados por outros meios).


49
" assertgeralmente gera uma exceção" - em C ++ não surge "exceção" que chama abortar ... é um pouco diferente.
Artyom

5
Não acho que essa resposta seja sobre os mesmos idiomas em que a pergunta está marcada (C e C ++). Em C e C ++, assert não gera uma exceção, possui parênteses em torno de seu argumento e o #caractere não introduz um comentário.
Steve Jessop

Aqui estão suas opções: Faça a resposta community-wiki e edite sua pergunta removendo as coisas antigas, pedindo a outras pessoas para colocar as informações corretas. Dessa forma, os votos negativos não afetarão seu representante e as pessoas poderão melhorar a resposta.
Johannes Schaub - litb 17/10/2009

2
length> = 0 também será falso se length for NaN
Andreas

1
Atualmente, no VS 2015, a declaração com uma mensagem de erro não funcionará porque está com defeito. Deve ser #assert("error message", expression)
Dooskington

102

O assert declaração computador é análoga à declaração make certeza em Inglês.


131
Bem, não exatamente. “Verifique se a luz está apagada” significa “verifique a luz e apague-a se estiver acesa”, não “veja se a luz está apagada e, se não estiver, por favor, exploda”. Eu diria que "verificação dupla" é uma tradução mais próxima.
Lucas Maurer

7
@ Lucas, que ilustra as maravilhas do idioma inglês, na medida em que o idioma oferece muitas maneiras de dizer a mesma coisa. Mas considere afirmar (comprimento> 0). Portanto, podemos traduzir isso para "verificar duas vezes o comprimento maior que zero" ou "garantir que o comprimento seja maior que zero" . Enquanto claramente ambas as opções funcionam, eu ainda prefiro o meu;)
Blake7

4
Bem, mas a outra interpretação é " tornar o comprimento maior que zero". Portanto, há um pouco mais de ambiguidade.
Lucas Maurer

29
É mais parecido com o verbo em inglês "assert"
Steve Carter

De fato, "verifique se" pode ser interpretado como "verifique e, se não estiver ok, altere".
Erik Bongers

14

Dê uma olhada

programa de exemplo assert () em C ++

Muitos compiladores oferecem uma macro assert (). A macro assert () retorna TRUE se seu parâmetro avaliar TRUE e executar algum tipo de ação se avaliar FALSE. Muitos compiladores abortam o programa em um assert () que falha; outros vão lançar uma exceção

Um recurso poderoso da macro assert () é que o pré-processador a recolhe em nenhum código se DEBUG não estiver definido. É uma grande ajuda durante o desenvolvimento e, quando o produto final é lançado, não há penalidade no desempenho nem aumento no tamanho da versão executável do programa.

Por exemplo

#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

11
Não deve ser "se NDEBUG estiver definido"?
1513 RichN

2
O que são esses "muitos compiladores"? MSVC e GCC são ambos os padrões compatíveis com este. Quais compiladores não compatíveis: não têm afirmação; não imprima uma mensagem e aborte quando uma declaração falhar; usar DEBUG em vez do NDEBUG adequado?
21608 Steve Jessop #

lmao, é claro que é um site chamado java-samples que faz isso tão errado.
underscore_d

6

A função assert () pode diagnosticar erros do programa. Em C, é definido em <assert.h>, e em C ++, é definido em <cassert>. Seu protótipo é

void assert(int expression);

A expressão do argumento pode ser qualquer coisa que você queira testar - uma variável ou qualquer expressão C. Se a expressão for avaliada como TRUE, assert () não fará nada. Se a expressão for avaliada como FALSE, assert () exibirá uma mensagem de erro no stderr e interromperá a execução do programa.

Como você usa assert ()? É usado com mais freqüência para rastrear erros do programa (que são diferentes dos erros de compilação). Um bug não impede a compilação de um programa, mas causa resultados incorretos ou a execução incorreta (travando, por exemplo). Por exemplo, um programa de análise financeira que você está escrevendo pode ocasionalmente fornecer respostas incorretas. Você suspeita que o problema seja causado pela variável interest_rate assumindo um valor negativo, o que nunca deve acontecer. Para verificar isso, coloque a declaração

afirmar (interest_rate> = 0); nos locais do programa em que interest_rate é usado. Se a variável se tornar negativa, a macro assert () o alertará. Você pode então examinar o código relevante para localizar a causa do problema.

Para ver como assert () funciona, execute o programa de exemplo abaixo . Se você digitar um valor diferente de zero, o programa exibirá o valor e será encerrado normalmente. Se você digitar zero, a macro assert () força o encerramento anormal do programa. A mensagem de erro exata que você vê depende do seu compilador, mas aqui está um exemplo típico:

Falha na asserção: x, lista de arquivos19_3.c, linha 13 Observe que, para que assert () funcione, seu programa deve ser compilado no modo de depuração. Consulte a documentação do compilador para obter informações sobre como ativar o modo de depuração (como explicado em um momento). Quando você compila posteriormente a versão final no modo de liberação, as macros assert () são desabilitadas.

 int x;

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

 assert(x >= 0);

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

Digite um valor inteiro: 10

Você digitou 10.

Digite um valor inteiro: -1

Mensagem de erro: Finalização anormal do programa

Sua mensagem de erro pode ser diferente, dependendo do sistema e do compilador, mas a ideia geral é a mesma.


Você explicou como seu programa de amostra funciona com assert. Não como se afirma. Como termina o programa de maneira anormal? isso lança algum tipo de exceção? Que tipo? Isso cria um sinal especial? que sinal? As asserções podem ser "capturadas" por qualquer tipo de mecanismo try-catch do C ++?
Motti Shneor 14/09/16

4

Coisas como 'gera exceção' e 'interrompe a execução' podem ser verdadeiras para a maioria dos compiladores, mas não para todos. (BTW, existem declarações de afirmação que realmente lançam exceções?)

Aqui está um significado interessante e ligeiramente diferente de afirmação usado pelo c6x e outros compiladores de TI: ao ver determinadas declarações de afirmação, esses compiladores usam as informações nessa declaração para executar certas otimizações. Malvado.

Exemplo em 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;
}

Isso informa ao compilador que as matrizes estão alinhadas nos limites de 32 bits, para que o compilador possa gerar instruções específicas feitas para esse tipo de alinhamento.


1
Então, o que eles fazem se a declaração for falsa e o NDEBUG não estiver definido? Se esta é a versão do assert de <assert.h>, o padrão exige que imprima uma mensagem e aborte. Obviamente, o padrão não diz que eles não podem otimizar com base na verdade da declaração, mas para serem compatíveis, eles ainda precisam abortar se for falso.
21609 Steve Jessop #

1
eles seguem o comportamento padrão
Stijn

1

Rascunho padrão do C ++ 11 N3337

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

19.3 Afirmações

1 O cabeçalho <cassert>, descrito em (Tabela 42), fornece uma macro para documentar as asserções do programa C ++ e um mecanismo para desativar as verificações de asserção.

2 O conteúdo é o mesmo que o cabeçalho da biblioteca Standard C <assert.h>.

Esboço padrão C99 N1256

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

7.2 Diagnósticos <assert.h>

1 O cabeçalho <assert.h>define a macro assert e se refere a outra macro, NDEBUGque não é definida por <assert.h>. Se NDEBUGfor definido como um nome de macro no ponto no arquivo de origem em que <assert.h> está incluído, a macro assert é definida simplesmente como

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

A macro assert é redefinida de acordo com o estado atual do NDEBUG cada vez que <assert.h>é incluído.

2. A macro de afirmação deve ser implementada como uma macro, não como uma função real. Se a definição de macro for suprimida para acessar uma função real, o comportamento será indefinido.

7.2.1 Diagnóstico do programa

7.2.1.1 A macro assert

Sinopse

1

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

Descrição

2 A macro assertiva coloca testes de diagnóstico em programas; expande para uma expressão nula. Quando é executada, se a expressão (que deve ter um tipo escalar) for falsa (ou seja, comparável a 0), a macro assertiva grava informações sobre a chamada específica que falhou (incluindo o texto do argumento, o nome da variável arquivo de origem, o número de linha de origem, e o nome da função envolvendo - os últimos são, respectivamente, os valores das macros de pré-processamento __FILE__e __LINE__e do identificador __func__) sobre o fluxo de erro padrão em um formato definido pela implementação. 165) Em seguida, chama a função abortar.

Devoluções

3 A macro assert não retorna nenhum valor.


1

Existem três razões principais para usar a função assert () sobre a normal if else e printf

  1. A função assert () é usada principalmente na fase de depuração, é tedioso escrever se mais com uma instrução printf toda vez que você deseja testar uma condição que pode nem aparecer no código final.

  2. Em grandes implantações de software, assert é muito útil, onde você pode fazer o compilador ignorar as instruções assert usando a macro NDEBUG definida antes de vincular o arquivo de cabeçalho para a função assert ().

  3. assert () é útil quando você está projetando uma função ou algum código e deseja ter uma idéia do que limita o código e que não funcionará e, finalmente, inclui um if else para avaliá-lo, basicamente com suposições.


0

É uma função que interromperá a execução do programa se o valor avaliado for falso. Geralmente, ele é cercado por uma macro para que não seja compilado no binário resultante quando compilado com as configurações de versão.

Ele foi projetado para ser usado para testar as suposições que você fez. Por exemplo:

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

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

O ideal que você quer é que você possa cometer um erro no seu programa, como chamar uma função com argumentos inválidos, e você pressionar uma afirmação antes que ela segfaults (ou falhe ao funcionar conforme o esperado)


por que simplesmente não usamos if & else e adicionamos algumas informações de registro?
Asad Khan

1
Porque você nunca deve passar um ponteiro nulo para strcpy. É uma daquelas coisas que não deveriam acontecer. Se um ponteiro nulo tiver sido passado, isso indica que algo em um nível superior está errado. Na melhor das hipóteses, você acaba tendo que travar o programa mais longe do problema devido a valores de dados inesperados (dest sendo incorreto ou nulo).
Yacoby 30/10/2009

-5

Além disso, você pode usá-lo para verificar se a alocação dinâmica foi bem-sucedida.

Exemplo 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.

Igual a:

if (p == NULL) {
    cout << "dynamic allocation failed" << endl;
    exit(1);
}

3
Não. newLança uma exceção na falha de alocação, a menos que você especifique nothrow(o que você não fez aqui). Além disso, sua formatação é estranha e exité má.
Lightness Races in Orbit

Sim você está certo. Eu esqueci de adicionar não. Adoraria ver como você vai usar em vez de saída
Sadikov

1
@Sadikov Qualquer outra pessoa poderia lidar com essa condição de erro usando código que não é completamente removido ao criar no modo de liberação , deixando seus usuários sem proteção e à mercê de comportamento indefinido se uma condição prévia não for atendida e, graças a isso, for nunca verificado e pego . assert()é apenas para depurar e eliminar coisas que nunca deveriam nunca acontecer - muito antes de uma compilação de lançamento ser feita.
underscore_d
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.