Uma asserção é uma condição que se deve sempre verificar-se num determinado ponto do programa.
#include <assert.h>
assert( int cond );
cond
for diferente de 0: não faz nadacond
for 0: imprime uma mensagem de erro e termina imediatamente a execução do programaprog: some_file.c:16: some_func: Assertion ... failed.
#include <assert.h>
int main(void) {
int x = 5, y = -3;
assert( x + y == 2 );
// esta asserção é válida
y = x;
assert( x + y == 2 );
// esta asserção já não é válida;
// o programa termina imediatamente!
printf("fim\n");
}
Exprimir uma pré-condição pode ajudar a detetar erros na chamada de uma função.
Testar se um ano é bissexto (exercício 4.6):
Esta correção ao calendário foi introduzida pelo papa Gregório XIII em 1582.
Logo: as regras acima só se aplicam a partir dessa data.
https://pt.wikipedia.org/wiki/Calend%C3%A1rio_gregoriano).
int bissexto(int n) {
// n é o ano que queremos testar;
// pré-condição: deve ser posterior a 1582
assert(n >= 1582);
// OK, vamos considerar os casos acima
if (n%400 == 0)
return TRUE;
if (n%4 == 0 && n%100 != 0)
return TRUE;
return FALSE;
}
int main(void) {
...
}
Introduza um ano: 2000
2000 foi bissexto
Introduza um ano: 1384
bissexto: ...: Assertion `n >= 1582' failed.
Calcular a pontuação do SCRABBLE para uma cadeia de letras (Exercício 7.6):
scrabble("PITFALL")
deve retornar 12;Pré-condição: a cadeia deve conter apenas letras maiúsculas 'A'
, 'B'
, ..., 'Z'
.
int scrabble(char str[]) {
// pré-condição: apenas letras maiúsculas
for (int i=0; str[i]!='\0'; i++) {
assert(str[i]>='A' && str[i]<='Z');
}
// OK, vamos calcular a pontuação
...
}
Exprimir uma pós-condição pode ajudar a detetar erros na implementação de uma função.
Gerar um número inteiro pseudo-aleatório ímpar entre 1 e 99 (última alínea do exercício 6.1).
int gerador(void) {
int n;
n = rand()%100 + 1; // NB: ERRADO!
// pós-condição: o resultado está no
// intervalo esperado e é ímpar
assert(n>=1 && n<=99 && n%2 == 1);
return n;
}
Vamos testar um gerador efetuando várias experiências:
int main(void) {
for(int i = 0; i<1000; i++) {
int n = gerador();
printf("%d\n", n);
}
}
A asserção falha na execução: detetamos um erro no gerador!
Podemos separar as asserções para compreender o que falha:
assert(n >= 1);
assert(n <= 99);
assert(n%2 == 1);
A primeira asserção passa sempre mas a segunda e terceira podem falhar!
Ou seja:
(Exercicio: corrigir o gerador.)
return
int elimrep(int v[], int n);
v
int elimrep(int vec[], int n) {
int k = 0;
for(int i = 0; i < n; i++) {
assert(0 <= k && k <= i);
assert(0 <= i && i < n);
int val = vec[i];
if(!ocorre(vec, k, val)) {
vec[k++] = val;
// valor não repetido
}
}
return k;
}
Assert failed
em vez de Segmentation Fault
Distinguir entre:
uma situação que não deve ocorrer; por exemplo: usar um índice inválido ou dividir por zero.
uma situação que pode ocorrer e que devemos tratar; por exemplo: um input incompleto do utilizador.
Asserções são um mecanismo para detetar o primeiro tipo de erros — não para tratar os segundos.