C ++ 'da __FILE__, __LINE__ ve __FUNCTION__ kullanımı


158

C ++ derleyicisi destekleri onları, belirli bir nedeni var olduğunu varsayarsak değil kullanımına __FILE__, __LINE__ve __FUNCTION__günlüğü ve hata ayıklama amacıyla?

Öncelikle kullanıcıya yanıltıcı veriler (örneğin, optimizasyonun sonucu olarak yanlış satır numarasını veya işlevi bildirme) vermek veya sonuç olarak bir performans isabeti almakla ilgileniyorum.

Temelde, güvenebileceğim __FILE__, __LINE__ve __FUNCTION__karşı her zaman doğru olanı yapmak?


LINE doğru olanı yapmalıdır. PRETTY_FUNCTION dahil olmak üzere onu ve kohortlarını yoğun bir şekilde kullandım . ... Ama ... LINEey, ben ţu anda LINE'nin yatýţtýđý koda bakýyorum . Muhtemelen try / catch istisna işleme için bir catch bloğunda olduğu için.
Krazy Glew

Yanıtlar:


191

__FUNCTION__standart değildir, __func__C99 / C ++ 11'de bulunur. Diğerleri ( __LINE__ve __FILE__) gayet iyi.

Her zaman doğru dosyayı ve satırı bildirir (ve __FUNCTION__/ seçeneğini kullanmayı seçerseniz işlevini gösterir __func__). Derleme zamanı makro genişlemesi olduğundan optimizasyon bir faktör değildir; o olacak asla herhangi bir şekilde performansını etkileyecektir.


3
__func__C ++ 'da bir problemdir. C99, varsayılan argümanlar hakkında bir şey söylemez ve bu nedenle __func__, C ++ 'da nasıl davranılması gerektiği çok açık olmayan durumlar .
wilhelmtell

4
@ thr: iyi bir noktaya değinirken. Ben __func__c ++ değil, c ++ var oldukça açıktı . Ne olursa olsun, __func__c ++ 'da makul bir uygulama sadece karışık adı ile sonuç olacağını düşünüyorum . Derleyici yazar olmadığımdan, bu benim çağrım değil.
Evan Teran

Hangi derleyiciler desteklemiyor __FUNCTION__? Son gcc dışındaki hangi derleyiciler bunu makro değil değişken olarak ele alıyor?
havza

36
__func__artık C ++ 11 standardında.
VX

38

Nadir durumlarda, __LINE__başka bir şeye verilen çizgiyi değiştirmek yararlı olabilir . Ben GNU yapılandırmak bazı testler için orijinal kaynak dosyalarında görünmeyen satırlar arasında bazı voodoo ekledikten sonra uygun satır numaralarını bildirmek için yaptığını gördüm. Örneğin:

#line 100

Aşağıdaki satırlar __LINE__100 ile başlayacaktır. İsteğe bağlı olarak yeni bir dosya adı ekleyebilirsiniz.

#line 100 "file.c"

Çok nadiren faydalıdır. Ancak ihtiyaç duyulursa, bildiğim alternatifler yoktur. Aslında, çizgi yerine, yukarıdaki iki formdan herhangi biriyle sonuçlanması gereken bir makro da kullanılabilir. Boost önişlemci kütüphanesini kullanarak geçerli satırı 50 artırabilirsiniz:

#line BOOST_PP_ADD(__LINE__, 50)

Ben size kullanımı hakkında sorulan beri söz faydalıdır düşünce __LINE__ve __FILE__. Biri C ++ 'dan yeterince sürpriz alamaz :)

Edit: @Jonathan Leffler yorumlarda bazı daha iyi kullanım durumları sağlar:

#Line ile uğraşmak, kullanıcının C kodunda bildirilen hataları kullanıcının kaynak dosyasıyla uyumlu tutmak isteyen ön işlemciler için çok kullanışlıdır. Yacc, Lex ve (evde daha fazlası) ESQL / C ön işlemcileri bunu yapıyor.


29

Bilginize: g ++ standart olmayan __PRETTY_FUNCTION__ makrosunu sunar. Şimdiye kadar C99 __func__ hakkında bir şey bilmiyordum (teşekkürler Evan!). Ben ekstra sınıf kapsamı için kullanılabilir olduğunda hala __PRETTY_FUNCTION__ tercih düşünüyorum.

Not:

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
__PRETTY_FUNCTION__ hakkında bilgi sahibi olmak güzel. Çok kullanışlı!
Zheng Qu

8

Şahsen, bunları hata ayıklama mesajları dışında herhangi bir şey için kullanmakta isteksizim. Bunu yaptım, ancak bu tür bilgileri müşterilere veya son kullanıcılara göstermemeye çalışıyorum. Müşterilerim mühendis değil ve bazen bilgisayar bilgisine sahip değiller. Bu bilgileri konsola kaydedebilirim, ancak dediğim gibi, hata ayıklama yapıları veya dahili araçlar dışında isteksizce. Yine de sahip olduğunuz müşteri tabanına bağlı olduğunu düşünüyorum.


29
"Bu bilgiyi konsola kaydedebilirim" - ya da daha iyisi: bir dosyaya giriş yapın, böylece bir şeyler ters giderse müşteriden size göndermesini isteyebilirsiniz ...
Christoph

7

C ++ 20 std::source_location

C ++ sonunda makro olmayan bir seçenek ekledi ve C ++ 20 yaygınlaştığında gelecekte bir noktada baskın olacak:

Belgeler diyor ki:

constexpr const char * işlev_adı () const noexcept;

6 Döndürür: Bu nesne bir işlev gövdesindeki bir konumu temsil ediyorsa, işlev adına karşılık gelmesi gereken, uygulama tanımlı bir NTBS döndürür. Aksi takdirde, boş bir dize döndürür.

burada NTBS "Boş Sonlandırılmış Bayt Dizesi" anlamına gelir.

Destek GCC'ye geldiğinde bir deneyeceğim, GCC 9.1.0 g++-9 -std=c++2ahala desteklemiyor.

https://en.cppreference.com/w/cpp/utility/source_location talep kullanımı şöyle olacaktır:

#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!");
}

Olası çıktı:

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

__PRETTY_FUNCTION__vs __FUNCTION__vs __func__vsstd::source_location::function_name

Yanıt verdi: __PRETTY_FUNCTION__, __FUNCTION__, __func__ arasındaki fark nedir?


1
Şu <experimental/source_location>anki gcc-9'da var.
陈浩南

5

Onları her zaman kullanıyorum. Endişelediğim tek şey günlük dosyalarında IP vermektir. İşlev adlarınız gerçekten iyiyse, bir ticari sırrı daha kolay ortaya çıkarıyor olabilirsiniz. Hata ayıklama sembolleri ile nakliye gibi şeyler bulmak sadece daha zor. Olguların% 99,999'unda kötü bir şey gelmeyecektir.


1
Ortaya çıkmak için iyi bir nokta. Bu bilgileri, stringsdizeden benzer tüm verileri yürütülebilir dosyadan ayıklamak için yardımcı programı kullanarak ayıklamak çok önemlidir . Sıkıştırılmış yürütülebilir dosyalar bile çıkarılabilir. Bir müşteri sitesine ne gönderdiğinize çok dikkat edin. Çoğu zaman rakipler, çalıştırılmaları gerekmese de, yürütülebilir dosyalarınıza erişebilirler.
Marty

İkili dosyanızdaki tüm dize değişmezlerini gizlemek için bir arama tablosu veya bitsel XOR vb. Kullanan constexpr ile mümkündür. Arama yaparsanız orada çeşitli örnekler vardır. Tabii ki gizleme sadece gizliliktir ve güvenlik değildir, ancak dosyalarınızı ve işlevlerinizi ikili dosyada açıkça göstermek istemiyorsanız, bu bir seçenektir.
idij
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.