__FILE__, __LINE__, dan __FUNCTION__ penggunaan dalam C ++


158

Dengan anggapan bahwa kompiler C ++ Anda mendukungnya, apakah ada alasan khusus untuk tidak menggunakannya __FILE__, __LINE__dan __FUNCTION__untuk tujuan logging dan debugging?

Saya terutama prihatin dengan memberikan data yang menyesatkan pengguna — misalnya, melaporkan nomor baris yang salah atau fungsi sebagai hasil dari optimasi — atau sebagai akibatnya mendapatkan hasil yang mengejutkan.

Pada dasarnya, dapatkah saya percaya __FILE__, __LINE__dan __FUNCTION__untuk selalu melakukan hal yang benar?


LINE harus melakukan hal yang benar. Saya telah menggunakannya dan kohortnya secara ekstensif, termasuk PRETTY_FUNCTION . ... Tapi ... yah, saya baru saja melihat kode di mana LINE berada. Mungkin karena itu di blok tangkap untuk penanganan pengecualian coba / tangkapan.
Krazy Glew

Jawaban:


191

__FUNCTION__tidak standar, __func__ada di C99 / C ++ 11. Yang lain ( __LINE__dan __FILE__) baik-baik saja.

Itu akan selalu melaporkan file dan baris yang tepat (dan berfungsi jika Anda memilih untuk menggunakan __FUNCTION__/ __func__). Optimalisasi adalah non-faktor karena merupakan ekspansi makro waktu kompilasi; itu tidak akan pernah mempengaruhi kinerja dengan cara apa pun.


3
__func__adalah jenis masalah di C ++. C99 tidak mengatakan sepatah kata pun tentang argumen default dan sebagainya, kasus di mana tidak begitu jelas bagaimana __func__seharusnya berperilaku di C ++.
wilhelmtell

4
@ thr: saat Anda membuat poin yang bagus. Saya cukup jelas yang __func__ada di c99, bukan c ++. Terlepas dari itu, saya pikir implementasi yang masuk akal __func__dalam c + + hanya akan menghasilkan nama hancur. Karena saya bukan penulis kompiler, itu bukan panggilan saya.
Evan Teran

Kompiler apa yang tidak didukung __FUNCTION__sama sekali? Kompiler apa kecuali gcc baru-baru ini memperlakukan ini sebagai variabel, bukan makro?
baskom

36
__func__sekarang dalam standar C ++ 11.
VX

38

Dalam kasus yang jarang terjadi, akan berguna untuk mengubah garis yang diberikan oleh __LINE__kepada hal lain. Saya telah melihat konfigurasi GNU melakukan itu untuk beberapa tes untuk melaporkan nomor baris yang sesuai setelah itu memasukkan beberapa voodoo antara baris yang tidak muncul dalam file sumber asli. Sebagai contoh:

#line 100

Akan membuat baris berikut dimulai dengan __LINE__100. Anda dapat menambahkan nama file baru secara opsional

#line 100 "file.c"

Ini jarang berguna. Tetapi jika dibutuhkan, tidak ada alternatif yang saya tahu. Sebenarnya, alih-alih baris, makro dapat digunakan juga yang harus menghasilkan salah satu dari dua bentuk di atas. Menggunakan perpustakaan preprocessor boost, Anda dapat menambah baris saat ini dengan 50:

#line BOOST_PP_ADD(__LINE__, 50)

Saya pikir sangat berguna untuk menyebutkannya karena Anda bertanya tentang penggunaan __LINE__dan __FILE__. Satu tidak pernah mendapat cukup kejutan dari C ++ :)

Sunting: @Jonathan Leffler memberikan beberapa kasus penggunaan yang lebih baik dalam komentar:

Messing dengan #line sangat berguna untuk pra-prosesor yang ingin menjaga kesalahan yang dilaporkan dalam kode C pengguna sesuai dengan file sumber pengguna. Yacc, Lex, dan (lebih banyak di rumah bagi saya) ESQL / C preprocessor melakukan itu.


29

FYI: g ++ menawarkan makro __PRETTY_FUNCTION__ non-standar. Sampai sekarang saya tidak tahu tentang C99 __func__ (terima kasih Evan!). Saya pikir saya masih lebih suka __PRETTY_FUNCTION__ bila tersedia untuk pelingkupan kelas tambahan.

PS:

static string  getScopedClassMethod( string thePrettyFunction )
{
  size_t index = thePrettyFunction . find( "(" );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( index );

  index = thePrettyFunction . rfind( " " );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( 0, index + 1 );

  return thePrettyFunction;   /* The scoped class name. */
}

2
Senang mengetahui tentang __PRETTY_FUNCTION__. Sangat berguna!
Zheng Qu

8

Secara pribadi, saya enggan menggunakan ini untuk apa pun selain pesan debugging. Saya telah melakukannya, tetapi saya berusaha untuk tidak menunjukkan informasi seperti itu kepada pelanggan atau pengguna akhir. Pelanggan saya bukan insinyur dan terkadang tidak paham komputer. Saya mungkin mencatat info ini ke konsol, tetapi, seperti yang saya katakan, dengan enggan kecuali untuk debug builds atau untuk alat internal. Saya kira itu tergantung pada basis pelanggan yang Anda miliki.


29
"Saya mungkin mencatat info ini ke konsol" - atau lebih baik lagi: login ke file sehingga jika terjadi kesalahan, Anda dapat meminta pelanggan untuk mengirimkannya kepada Anda ...
Christoph

7

C ++ 20 std::source_location

C ++ akhirnya menambahkan opsi non-makro, dan itu kemungkinan akan mendominasi di beberapa titik di masa mendatang ketika C ++ 20 menyebar luas:

Dokumentasi mengatakan:

constexpr const char * function_name () const noexcept;

6 Pengembalian: Jika objek ini mewakili posisi di tubuh fungsi, mengembalikan NTBS yang ditentukan implementasi yang harus sesuai dengan nama fungsi. Jika tidak, kembalikan string kosong.

di mana NTBS berarti "Null Terminated Byte String".

Saya akan mencobanya ketika dukungan datang ke GCC, GCC 9.1.0 dengan g++-9 -std=c++2amasih tidak mendukungnya.

https://en.cppreference.com/w/cpp/utility/source_location klaim penggunaan akan seperti:

#include <iostream>
#include <string_view>
#include <source_location>

void log(std::string_view message,
         const std::source_location& location std::source_location::current()
) {
    std::cout << "info:"
              << location.file_name() << ":"
              << location.line() << ":"
              << location.function_name() << " "
              << message << '\n';
}

int main() {
    log("Hello world!");
}

Output yang mungkin:

info:main.cpp:16:main Hello world!

__PRETTY_FUNCTION__vs __FUNCTION__vs __func__vsstd::source_location::function_name

Dijawab di: Apa perbedaan antara __PRETTY_FUNCTION__, __FUNCTION__, __func__?


1
Ada <experimental/source_location>dalam gcc-9 saat ini.
陈浩南

5

Saya menggunakannya sepanjang waktu. Satu-satunya hal yang saya khawatirkan adalah memberikan IP dalam file log. Jika nama fungsi Anda benar-benar bagus, Anda mungkin membuat rahasia dagang lebih mudah terungkap. Ini seperti pengiriman dengan simbol debug, hanya lebih sulit untuk menemukan sesuatu. Dalam 99,999% kasus tidak ada hal buruk yang akan terjadi.


1
Poin yang bagus untuk diangkat. Sangat mudah untuk mengekstrak informasi ini menggunakan stringsutilitas untuk mengekstrak semua data seperti string dari yang dapat dieksekusi. Bahkan executable terkompresi dapat diekstraksi. Berhati-hatilah dengan apa yang Anda kirim ke situs pelanggan. Sering kali pesaing mampu mendapatkan yang dapat dieksekusi Anda, meskipun mereka tidak seharusnya melakukannya.
Marty

Mungkin dengan constexpr yang menggunakan tabel pencarian atau XOR bitwise, dll. Untuk mengaburkan string string apa pun dalam biner Anda. Ada berbagai contoh di luar sana jika Anda mencari. Tentu saja kebingungan hanyalah ketidakjelasan dan bukan keamanan, tetapi jika Anda tidak ingin membuat file dan fungsi Anda jelas dalam biner itu adalah pilihan.
idij
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.