Apa fungsi "menegaskan"?

262

Saya telah mempelajari tutorial OpenCV dan menemukan assertfungsinya; apa fungsinya?

Eomer
sumber
20
Perhatikan catatan dari man assert: "assert () diimplementasikan sebagai makro; jika ekspresi yang diuji memiliki efek samping, perilaku program akan berbeda tergantung pada apakah NDEBUG didefinisikan. Ini dapat membuat Heisenbugs yang hilang saat debugging dihidupkan . "
Johannes Schaub - litb
35
@ S.Lott sekarang orang yang mencari di google akan menemukan halaman ini sebagai salah satu hasil pencarian teratas, memberikan jawaban yang bagus ditinjau oleh rekan mereka untuk pertanyaan mereka, dan mempromosikan Stack Overflow pada saat yang sama, jadi ini adalah +1 dari saya!
Matt Grum
6
Ini -1 dari saya. Hasil pencarian teratas adalah dokumentasi yang seharusnya dikonsultasikan oleh OP.
Lightness Races in Orbit
9
@LightnessRacesinOrbit. Sebut saya malas, tapi saya lebih suka menggunakan bacaan dokumentasi yang ringkas, ringkas, dan menjelaskan yang disediakan oleh pengguna SO yang berpengetahuan luas seperti Anda. Terima kasih saya yang tulus :)
Tyson Hilmer

Jawaban:

298

assertakan menghentikan program (biasanya dengan pesan yang mengutip pernyataan tegas) jika argumennya ternyata salah. Ini biasa digunakan selama debugging untuk membuat program gagal lebih jelas jika kondisi yang tidak terduga terjadi.

Sebagai contoh:

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

Anda juga dapat menambahkan pesan yang lebih informatif untuk ditampilkan jika gagal seperti:

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

Atau yang lain seperti ini:

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

Saat Anda melakukan rilis (non-debug) build, Anda juga dapat menghapus overhead evaluasi assert pernyataan pernyataan dengan mendefinisikan NDEBUGmakro, biasanya dengan saklar kompiler. Akibat dari hal ini adalah bahwa program Anda seharusnya tidak pernah mengandalkan menjalankan makro yang tegas.

// 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);

Dari kombinasi panggilan program batal () dan tidak dijamin untuk melakukan apa pun, pernyataan hanya boleh digunakan untuk menguji hal-hal yang diasumsikan oleh pengembang alih-alih, misalnya, pengguna memasukkan angka daripada huruf (yang seharusnya ditangani dengan cara lain).

bdonlan
sumber
49
" assertBiasanya memunculkan eksepsi" - dalam C ++ tidak muncul "eksepsi" yang disebutnya batal ... sedikit berbeda.
Artyom
5
Saya tidak berpikir jawaban ini tentang bahasa yang sama dengan pertanyaan ditandai (C dan C ++). Dalam C dan C ++, menegaskan tidak memunculkan eksepsi, ia memiliki tanda kurung di sekitar argumennya, dan #karakter tidak memperkenalkan komentar.
Steve Jessop
Berikut adalah pilihan Anda: Buat komunitas-wiki jawaban dan edit pertanyaan Anda menghapus barang-barang lama, meminta orang lain untuk menempatkan informasi yang benar. Dengan begitu, downvotes tidak akan memengaruhi perwakilan Anda, dan orang-orang dapat meningkatkan jawabannya.
Johannes Schaub - litb
2
length> = 0 juga akan menjadi false jika panjangnya adalah NaN
Andreas
1
Saat ini, di VS 2015, pernyataan dengan pesan kesalahan tidak akan berfungsi karena tidak sesuai pesanan. Seharusnyaassert("error message", expression)
Dooskington
102

The menegaskan pernyataan komputer analog dengan pernyataan make yakin dalam bahasa Inggris.

Blake7
sumber
131
Ya tidak cukup. “Pastikan cahayanya mati” berarti “periksa cahayanya dan matikan jika menyala,” bukan “lihat apakah cahayanya mati dan jika tidak tolong meledak.” Saya akan mengatakan "periksa" adalah terjemahan yang lebih dekat.
Luke Maurer
7
@ Lukas, yang menggambarkan keajaiban bahasa Inggris, karena bahasa tersebut menawarkan banyak cara untuk mengatakan hal yang sama. Tetapi pertimbangkan menegaskan (panjang> 0). Jadi kita dapat menerjemahkannya menjadi "periksa ulang panjangnya lebih besar dari nol" atau "pastikan panjangnya lebih besar dari nol" . Meskipun jelas kedua opsi ini berfungsi, saya masih lebih suka opsi saya;)
Blake7
4
Ya, tapi interpretasi lainnya adalah " buat panjangnya lebih besar dari nol." Jadi ada sedikit ambiguitas.
Luke Maurer
29
Ini lebih mirip dengan kata kerja "assert" dalam bahasa Inggris
Steve Carter
Memang, "pastikan" dapat diartikan sebagai "centang, dan jika tidak ok, ubah".
Erik Bongers
14

Melihat

assert () contoh program dalam C ++

Banyak kompiler menawarkan makro assert (). Makro assert () mengembalikan TRUE jika parameternya mengevaluasi TRUE dan mengambil beberapa tindakan jika mengevaluasi FALSE. Banyak kompiler akan membatalkan program pada assert () yang gagal; yang lain akan melemparkan pengecualian

Salah satu fitur kuat dari makro assert () adalah bahwa preprocessor menciutkannya menjadi tidak ada kode sama sekali jika DEBUG tidak didefinisikan. Ini sangat membantu selama pengembangan, dan ketika produk akhir dikirimkan tidak ada penalti kinerja atau peningkatan ukuran versi program yang dapat dieksekusi.

Misalnya

#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
sumber
11
Tidak boleh "jika NDEBUG didefinisikan"?
RichN
2
Apa itu "banyak kompiler" tentang? MSVC dan GCC keduanya memenuhi standar yang satu ini. Kompiler mana yang tidak patuh: tidak memiliki penegasan; jangan cetak pesan dan batalkan ketika suatu pernyataan gagal; gunakan DEBUG alih-alih NDEBUG yang tepat?
Steve Jessop
lmao, tentu saja ini adalah situs web yang disebut sampel java yang salah paham.
underscore_d
6

Fungsi assert () dapat mendiagnosis bug program. Dalam C, didefinisikan dalam <assert.h>, dan dalam C ++ itu didefinisikan dalam <cassert>. Prototipenya adalah

void assert(int expression);

Ekspresi argumen dapat berupa apa pun yang ingin Anda uji - variabel atau ekspresi C apa pun. Jika ekspresi bernilai TRUE, menegaskan () tidak melakukan apa-apa. Jika ekspresi mengevaluasi ke FALSE, menegaskan () menampilkan pesan kesalahan pada stderr dan membatalkan eksekusi program.

Bagaimana Anda menggunakan menegaskan ()?Ini paling sering digunakan untuk melacak bug program (yang berbeda dari kesalahan kompilasi). Bug tidak mencegah program untuk dikompilasi, tetapi menyebabkannya untuk memberikan hasil yang salah atau berjalan dengan tidak benar (misalnya, mengunci). Misalnya, program analisis keuangan yang Anda tulis terkadang memberikan jawaban yang salah. Anda mencurigai bahwa masalah disebabkan oleh variabel interest_rate mengambil nilai negatif, yang seharusnya tidak pernah terjadi. Untuk memeriksa ini, tempatkan pernyataan

menegaskan (interest_rate> = 0); di lokasi dalam program di mana interest_rate digunakan. Jika variabel pernah menjadi negatif, makro assert () memberi tahu Anda. Anda kemudian dapat memeriksa kode yang relevan untuk menemukan penyebab masalah.

Untuk melihat cara kerja assert (), jalankan contoh program di bawah ini . Jika Anda memasukkan nilai bukan nol, program menampilkan nilai dan berakhir secara normal. Jika Anda memasukkan nol, makro pernyataan () memaksa penghentian program tidak normal. Pesan kesalahan persis yang Anda lihat akan tergantung pada kompiler Anda, tetapi inilah contoh khasnya:

Pernyataan gagal: x, file list19_3.c, baris 13 Perhatikan bahwa, agar assert () berfungsi, program Anda harus dikompilasi dalam mode debug. Lihat dokumentasi kompiler Anda untuk informasi tentang mengaktifkan mode debug (seperti dijelaskan sebentar lagi). Saat nanti Anda mengkompilasi versi final dalam mode rilis, makro assert () dinonaktifkan.

 int x;

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

 assert(x >= 0);

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

Masukkan nilai integer: 10

Anda memasukkan 10.

Masukkan nilai integer: -1

Pesan Kesalahan: Penghentian program yang tidak normal

Pesan kesalahan Anda mungkin berbeda, tergantung pada sistem dan kompiler Anda, tetapi gagasan umumnya sama.

Abhishek Kaushik
sumber
Anda menjelaskan bagaimana program sampel Anda bekerja dengan tegas. Bukan bagaimana menegaskan itu sendiri bekerja. Bagaimana cara mengakhiri program secara tidak normal? apakah itu melempar semacam pengecualian? Jenis apa? Apakah itu menciptakan sinyal khusus? sinyal apa? Bisakah pernyataan "tertangkap" oleh mekanisme try-catch C ++ apa pun?
Motti Shneor
4

Hal-hal seperti 'menimbulkan pengecualian' dan 'menghentikan eksekusi' mungkin benar untuk sebagian besar kompiler, tetapi tidak untuk semua. (BTW, apakah ada pernyataan tegas yang benar-benar memberikan pengecualian?)

Berikut adalah makna asersi yang menarik, sedikit berbeda yang digunakan oleh c6x dan kompiler TI lainnya: setelah melihat pernyataan tegas tertentu, kompiler ini menggunakan informasi dalam pernyataan itu untuk melakukan optimasi tertentu. Jahat.

Contoh dalam 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;
}

Ini memberitahu de compiler bahwa array disejajarkan pada batas 32-bit, sehingga kompiler dapat menghasilkan instruksi spesifik yang dibuat untuk perataan semacam itu.

stijn
sumber
1
Jadi apa yang mereka lakukan jika pernyataan itu salah dan NDEBUG tidak disetel? Jika ini adalah versi assert dari <assert.h>, maka standar mengharuskannya untuk mencetak pesan dan membatalkan. Jelas standar tidak mengatakan mereka tidak diizinkan untuk mengoptimalkan berdasarkan kebenaran pernyataan itu, tetapi untuk patuh mereka masih harus membatalkan jika itu salah.
Steve Jessop
1
mereka mengikuti perilaku standar
stijn
1

C ++ 11 N3337 konsep standar

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

19.3 Penegasan

1 Header <cassert>, dijelaskan dalam (Tabel 42), menyediakan makro untuk mendokumentasikan pernyataan program C ++ dan mekanisme untuk menonaktifkan pemeriksaan pernyataan.

2 Isi sama dengan tajuk pustaka C Standar <assert.h>.

C99 N1256 draft standar

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

7.2 Diagnostik <assert.h>

1 Header <assert.h>mendefinisikan makro pernyataan dan merujuk ke makro lain, NDEBUGyang tidak didefinisikan oleh <assert.h>. Jika NDEBUGdidefinisikan sebagai nama makro pada titik di file sumber di mana <assert.h> disertakan, makro pernyataan didefinisikan hanya sebagai

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

Makro menegaskan didefinisikan ulang sesuai dengan keadaan saat ini NDEBUG setiap kali <assert.h>disertakan.

2. Makro menegaskan harus diimplementasikan sebagai makro, bukan sebagai fungsi yang sebenarnya. Jika definisi makro ditekan untuk mengakses fungsi aktual, perilaku tidak terdefinisi.

7.2.1 Diagnostik program

7.2.1.1 Makro tegas

Ringkasan

1.

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

Deskripsi

2 Makro menegaskan menempatkan tes diagnostik ke dalam program; itu mengembang ke ekspresi kosong. Ketika dieksekusi, jika ekspresi (yang akan memiliki tipe skalar) salah (yaitu, sama dengan 0), makro menegaskan menulis informasi tentang panggilan tertentu yang gagal (termasuk teks argumen, nama file sumber, nomor baris sumber, dan nama fungsi melampirkan - yang terakhir masing-masing adalah nilai-nilai makro preprocessing __FILE__dan __LINE__dan pengidentifikasi __func__) pada aliran kesalahan standar dalam format yang ditentukan implementasi. 165) Ini kemudian memanggil fungsi batal.

Kembali

3 Makro menegaskan tidak mengembalikan nilai.

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

Ada tiga alasan utama untuk menggunakan fungsi assert () di atas normal jika lain dan printf

  1. Fungsi assert () terutama digunakan dalam fase debugging, itu membosankan untuk menulis jika lagi dengan pernyataan printf setiap kali Anda ingin menguji suatu kondisi yang bahkan mungkin tidak membuat jalannya dalam kode akhir.

  2. Dalam penyebaran perangkat lunak besar, pernyataan menjadi sangat berguna di mana Anda dapat membuat kompilator mengabaikan pernyataan pernyataan menggunakan makro NDEBUG yang ditentukan sebelum menautkan file header untuk fungsi assert ().

  3. assert () berguna ketika Anda sedang merancang suatu fungsi atau beberapa kode dan ingin mendapatkan ide tentang apa yang membatasi kode akan dan tidak bekerja dan akhirnya menyertakan jika ada untuk mengevaluasi itu pada dasarnya bermain dengan asumsi.

Nnaik
sumber
0

Ini adalah fungsi yang akan menghentikan eksekusi program jika nilai yang dievaluasi salah. Biasanya dikelilingi oleh makro sehingga tidak dikompilasi ke dalam biner yang dihasilkan ketika dikompilasi dengan pengaturan rilis.

Ini dirancang untuk digunakan untuk menguji asumsi yang telah Anda buat. Sebagai contoh:

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

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

Yang ideal yang Anda inginkan adalah bahwa Anda dapat membuat kesalahan dalam program Anda, seperti memanggil fungsi dengan argumen yang tidak valid, dan Anda menekan sebuah pernyataan sebelum segfaults (atau gagal berfungsi seperti yang diharapkan)

Yacoby
sumber
mengapa tidak kita gunakan saja jika & yang lain & tambahkan beberapa info masuk?
Asad Khan
1
Karena Anda seharusnya tidak pernah melewatkan pointer nol ke strcpy. Ini adalah salah satu hal yang tidak boleh terjadi. Jika sebuah null pointer telah dilewati, ini menunjukkan bahwa sesuatu pada level yang lebih tinggi telah kacau. Paling-paling Anda akhirnya harus crash program lebih jauh dari masalah karena nilai data yang tidak terduga (baik dest salah atau nol).
Yacoby
-5

Selain itu, Anda dapat menggunakannya untuk memeriksa apakah alokasi dinamis berhasil.

Contoh kode:

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.

Mirip dengan:

if (p == NULL) {
    cout << "dynamic allocation failed" << endl;
    exit(1);
}
Sadikov
sumber
3
Tidak. newMelempar pengecualian pada kegagalan alokasi kecuali Anda menentukan nothrow(yang tidak Anda lakukan di sini). Selain itu, format Anda aneh dan exitjahat.
Lightness Races in Orbit
Ya kamu benar. Saya lupa menambahkan tidak. Akan senang melihat bagaimana Anda akan menggunakan bukannya keluar
Sadikov
1
@Sadikov Orang lain akan menangani kondisi kesalahan seperti itu menggunakan kode yang tidak sepenuhnya dihapus ketika membangun dalam mode rilis , sehingga meninggalkan pengguna Anda tanpa perlindungan dan pada belas kasihan perilaku yang tidak terdefinisi jika prasyarat tidak terpenuhi dan, berkat ini, adalah tidak pernah memeriksa dan menangkap . assert()hanya untuk debugging dan menghilangkan hal-hal yang seharusnya tidak pernah terjadi - jauh sebelum rilis rilis dibuat.
underscore_d