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?

Killrazor
sumber
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.

zneak
sumber
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)

Andrei Bozantan
sumber
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 =)

Eugene Magdalits
sumber
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
19
BOOST_ASSERT_MSG(expre, msg)

http://www.boost.org/doc/libs/1_51_0/libs/utility/assert.html

Anda dapat menggunakannya secara langsung atau menyalin kode Boost. Perhatikan juga Boost assert hanya header, jadi Anda bisa mengambil file tunggal itu jika Anda tidak ingin menginstal semua Boost.

Nol
sumber
@Jichao, apa maksudmu dengan mengimplementasikan antarmuka tegas?
Tarc
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.

metamorfosis
sumber
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

Merlyn Morgan-Graham
sumber
-6

Untuk vc, tambahkan kode berikut di assert.h,

#define assert2(_Expression, _Msg) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Msg), _CRT_WIDE(__FILE__), __LINE__), 0) )
Jichao
sumber
11
Memodifikasi header kompiler Anda adalah ide yang buruk.
Ross Ridge