Tambahkan pesan khusus dengan tegas?


129

Apakah ada cara untuk menambah atau mengedit pesan yang dilontarkan dengan tegas? Saya ingin menggunakan sesuatu seperti

assert(a == b, "A must be equal to B");

Kemudian, kompiler menambahkan baris , waktu dan seterusnya ...

Apa itu mungkin?


Anda dapat mendefinisikan makro, seperti ini .
HelloGoodbye

Jawaban:


240

Peretasan yang saya lihat di sekitar adalah menggunakan &&operator. Karena pointer "benar" jika bukan nol, Anda dapat melakukan hal berikut tanpa mengubah kondisinya:

assert(a == b && "A is not equal to B");

Karena assertmenunjukkan kondisi yang gagal, itu akan menampilkan pesan Anda juga. Jika itu tidak cukup, Anda dapat menulis myAssertfungsi atau makro Anda sendiri yang akan menampilkan apa pun yang Anda inginkan.


27
Pilihan lain adalah membalikkan operan dan menggunakan operator koma. Anda membutuhkan tanda kurung tambahan sehingga koma tidak diperlakukan sebagai pembatas di antara argumen:assert(("A must be equal to B", a == b));
Keith Thompson

3
Akan lebih baik, meskipun, untuk dapat mencetak nilai-nilai variabel, seperti pada:assert(a == b && "A (" << A << ") is not equal to B (" << B << ")");
Frank

7
@ Sejujurnya, printfmengembalikan nilai bukan nol jika itu mencetak sesuatu, sehingga Anda bisa melakukan sesuatu seperti assert(a == b && printf("a (%i) is not equal to b (%i)", a, b)), meskipun pada saat itu Anda mungkin harus menulis pembungkus tegas Anda sendiri.
zneak

1
Kode yang salah! Saya tidak mengerti ini! Jika a == b salah, ekspresi-dan juga harus salah, dan, oleh karena itu, string tidak boleh dievaluasi.
ragnarius

1
@ TUIlover, bukan itu cara kerja string C literal; mereka adalah konstanta waktu kompilasi dan penggunaannya dalam konteks ini secara sepele dioptimalkan. Tidak ada biaya runtime.
zneak

45

Pilihan lain adalah membalikkan operan dan menggunakan operator koma. Anda membutuhkan tanda kurung tambahan sehingga koma tidak diperlakukan sebagai pembatas di antara argumen:

assert(("A must be equal to B", a == b));

(ini disalin dari komentar di atas, untuk visibilitas yang lebih baik)


3
Ini adalah pendekatan yang hebat, dengan satu masalah kecil, ini akan menampilkan "peringatan: operan kiri dari operator koma tidak berpengaruh" ketika dikompilasi dalam g ++ dengan `-Wunused-value
v010dya

1
atau dengan makro: #ifndef m_assert #define m_assert (expr, msg) menegaskan ((msg, expr)) #endif
Szymon Marczak

Menggunakan pembungkus makro memungkinkan Anda menghindari peringatan gcc:#define m_assert(expr, msg) assert(( (void)(msg), (expr) ))
Jander

25

Inilah versi makro pernyataan saya, yang menerima pesan dan mencetak semuanya dengan jelas:

#include <iostream>

#ifndef NDEBUG
#   define M_Assert(Expr, Msg) \
    __M_Assert(#Expr, Expr, __FILE__, __LINE__, Msg)
#else
#   define M_Assert(Expr, Msg) ;
#endif

void __M_Assert(const char* expr_str, bool expr, const char* file, int line, const char* msg)
{
    if (!expr)
    {
        std::cerr << "Assert failed:\t" << msg << "\n"
            << "Expected:\t" << expr_str << "\n"
            << "Source:\t\t" << file << ", line " << line << "\n";
        abort();
    }
}

Sekarang, Anda bisa menggunakan ini

M_Assert(ptr != nullptr, "MyFunction: requires non-null argument");

Dan jika terjadi kegagalan Anda akan mendapatkan pesan seperti ini:

Penegasan gagal: MyFunction: membutuhkan argumen yang bukan nol

Diharapkan: ptr! = Nullptr

Sumber: C: \ MyProject \ src.cpp, baris 22

Bagus dan bersih, jangan ragu untuk menggunakannya dalam kode Anda =)


Bagus Sangat berguna
Killrazor

Saya agak bingung. Apakah #Expr diperlakukan sebagai string untuk substitusi langsung? Apa perbedaan antara #Expr dan Expr?
Minh Tran

@ MinhTran Mari kita asumsikan bahwa kondisi tegas Anda x == y. Kemudian Expr akan diperluas ke if( !(x == y))dan di sinilah kondisinya diperiksa, dan #Expr akan diperluas ke string literal "x == y", yang kemudian kita masukkan ke dalam pesan kesalahan.
Eugene Magdalits

Sayangnya, solusi ini menyebabkan perilaku tidak terdefinisi karena menggunakan pengidentifikasi yang dicadangkan.
Ingat Monica


7

Karena jawaban zneak agak rumit dalam kode, pendekatan yang lebih baik adalah dengan hanya mengomentari teks string yang sedang Anda bicarakan. yaitu.:

assert(a == b); // A must be equal to B

Karena pembaca kesalahan tegas akan mencari file dan baris pula dari pesan kesalahan, mereka akan melihat penjelasan lengkap di sini.

Karena, pada akhirnya, ini:

assert(number_of_frames != 0); // Has frames to update

membaca lebih baik dari ini:

assert(number_of_frames != 0 && "Has frames to update");

dalam hal penguraian kode manusia yaitu. keterbacaan. Juga bukan peretasan bahasa.


1
"Karena pembaca kesalahan tegas akan mencari file dan baris pula dari pesan kesalahan," - hanya jika mereka rajin.
Jason S

Hanya jika mereka ingin memperbaiki bug yang Anda maksud ... komentar yang konyol
metamorfosis

1
Tidak. Semakin mudah Anda membuat orang melihat masalahnya, semakin besar kemungkinan mereka akan mengambil tindakan.
Jason S

mengangkat bahu Tidak setuju.
metamorfosis

2

assert adalah kombinasi makro / fungsi. Anda dapat menentukan makro Anda sendiri / fungsi, menggunakan __FILE__, __BASE_FILE__, __LINE__dll, dengan fungsi sendiri yang mengambil pesan khusus


-6

Untuk vc, tambahkan kode berikut di assert.h,

#define assert2(_Expression, _Msg) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Msg), _CRT_WIDE(__FILE__), __LINE__), 0) )

11
Memodifikasi header kompiler Anda adalah ide yang buruk.
Ross Ridge
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.