__PRETTY_FUNCTION__, __FUNCTION__, __func__ में क्या अंतर है?


221

बीच क्या अंतर है __PRETTY_FUNCTION__, __FUNCTION__, __func__, और जहाँ वे दस्तावेज रहे हैं? मैं कैसे तय करूं कि किसका उपयोग करना है?

जवाबों:


266

__func__एक अव्यवस्थित रूप से घोषित पहचानकर्ता है जो किसी वर्ण सरणी चर में विस्तार करता है जिसमें फ़ंक्शन नाम होता है जब इसे किसी फ़ंक्शन के अंदर उपयोग किया जाता है। इसे C99 में C से जोड़ा गया था। से C99 §6.4.2.2 / 1:

पहचानकर्ता __func__को अनुवादक द्वारा स्पष्ट रूप से घोषित किया जाता है जैसे, प्रत्येक फ़ंक्शन परिभाषा के उद्घाटन ब्रेस के तुरंत बाद, घोषणा

static const char __func__[] = "function-name";

दिखाई दिया, जहाँ फ़ंक्शन-नाम lexically-enclosing फ़ंक्शन का नाम है। यह नाम फ़ंक्शन का अनियंत्रित नाम है।

ध्यान दें कि यह एक मैक्रो नहीं है और प्रीप्रोसेसिंग के दौरान इसका कोई विशेष अर्थ नहीं है।

__func__C ++ 11 में C ++ में जोड़ा गया था, जहां इसे "एक कार्यान्वयन-डे string ned स्ट्रिंग" (C ++ 11 C8.4.1 [dcl.fct.def.general] / 8) के रूप में निर्दिष्ट किया गया है, जो कि काफी नहीं है C. में विनिर्देशन के रूप में उपयोगी ( __func__C ++ में जोड़ने का मूल प्रस्ताव N1642 था )।

__FUNCTION__एक पूर्व-मानक विस्तार है जो कुछ सी संकलक समर्थन करते हैं (जीसीसी और विज़ुअल सी ++ सहित); सामान्य तौर पर, आपको इसका उपयोग करना चाहिए __func__जहां यह समर्थित है और केवल उपयोग करें __FUNCTION__यदि आप एक कंपाइलर का उपयोग कर रहे हैं जो इसका समर्थन नहीं करता है (उदाहरण के लिए, दृश्य C ++, जो C99 का समर्थन नहीं करता है और अभी तक C ++ 0x के सभी का समर्थन नहीं करता है, नहीं करता है प्रदान __func__)।

__PRETTY_FUNCTION__एक gcc एक्सटेंशन है जो ज्यादातर उसी तरह है __FUNCTION__, सिवाय इसके कि C ++ फ़ंक्शन के लिए फ़ंक्शन के हस्ताक्षर सहित "सुंदर" नाम शामिल है। दृश्य C ++ में एक समान (लेकिन काफी समान नहीं) विस्तार है __FUNCSIG__,।

अमानक मैक्रो के लिए, आप अपने संकलक के दस्तावेज से परामर्श करना चाहेंगे। Visual C ++ एक्सटेंशन C ++ कंपाइलर के "पूर्वनिर्धारित मैक्रोज़" के MSDN प्रलेखन में शामिल हैं । Gcc डॉक्यूमेंटेशन एक्सटेंशन को gcc डॉक्यूमेंटेशन पेज "फंक्शन नेम्स इन स्ट्रिंग्स" में वर्णित किया गया है


क्या आप C99 विनिर्देश (अपने स्रोत में एक अस्थायी लिंक है) से लिंक कर सकते हैं, जो जीतने वाले उत्तर की तरह दिखता है?
मैट जॉइनर

1
@ किंवदंतियां 2k: नहीं, यह C ++ 11 में "एक कार्यान्वयन-परिभाषित स्ट्रिंग" है। यह विनिर्देशन से वास्तविक भाषा है। See8.4.1 [dcl.fct.def.general] / 8 देखें।
जेम्स मैकनेलिस

2
ध्यान दें कि जबकि gcc और VC दोनों प्रदान करते हैं __FUNCTION__, वे थोड़ा अलग काम करते हैं। gcc के बराबर देता है __func__। वीसी अघोषित देता है, लेकिन अभी भी सजी है, नाम का संस्करण। "फू" नामक विधि के लिए, जीसीसी आपको देगा "foo", वीसी देगा "my_namespace::my_class::foo"
एड्रियन मैक्कार्थी

1
जो उत्सुक है वह यह है कि मैं एमएसवीसी 2017 सीई का उपयोग कर रहा हूं और जब मैं टाइप __PRETTY_FUNCTION__करता हूं तो यह उपलब्ध होने के रूप में सूची में दिखाई देता है और जब मैं अपने माउस को ऊपर ले जाता हूं, तो यह फ़ंक्शन नाम के बारे में जानकारी प्रदर्शित करता है, हालांकि यह संकलन करने में विफल रहता है।
फ्रांसिस कूगलर

1
@FrancisCugler इससे भी मैं आश्चर्यचकित था! इस पर मेरा सवाल देखें stackoverflow.com/questions/48857887/…
एडम बदुरा

108

मूल प्रश्न का पूरी तरह से उत्तर नहीं देने के बावजूद, यह शायद वही है जो अधिकांश लोग इसे देखना चाहते थे।

GCC के लिए:

petanb@debian:~$ cat test.cpp 
#include <iostream>

int main(int argc, char **argv)
{
    std::cout << __func__ << std::endl
              << __FUNCTION__ << std::endl
              << __PRETTY_FUNCTION__ << std::endl;
}
petanb@debian:~$ g++ test.cpp 
petanb@debian:~$ 
petanb@debian:~$ ./a.out 
main
main
int main(int, char**)

6
मैं जानता हूँ कि यह एक उचित जवाब नहीं है, लेकिन यह शायद क्या लगभग हर कोई है जो इस गूगल देखना चाहता था है :) (अगर वे खुद को प्रयास करने के लिए आलसी हैं)
Petr

5
फेयर कॉल, यह देखना अच्छा है।
मैट जॉइनर

13
क्लैंग 3.5 से समान आउटपुट
डोंचो गुंचेव

ठीक है, लेकिन __func__यह किसी अन्य फ़ंक्शन में एम्बेडेड होने पर काम करता है? कहते हैं कि मेरे पास फ़ंक्शन 1 है, यह कोई तर्क नहीं लेता है। function1 कॉल function2 जिसमें शामिल है __func__, कौन सा फ़ंक्शन नाम मुद्रित किया जाएगा, 1 या 2?
मार्कस जे।

@MarcusJ क्यों नहीं इसे स्वयं आज़माएं ... __func__एक मैक्रो है, यह आपके वर्तमान में जो भी फ़ंक्शन है, उसका अनुवाद करेगा। यदि आप इसे f1 में डालते हैं और f2 में f1 कॉल करते हैं, तो आपको हमेशा f1 मिलेगा।
पेट्र

41

__PRETTY_FUNCTION__ C ++ फीचर्स को हैंडल करता है: क्लासेस, नेमस्पेस, टेम्प्लेट और ओवरलोड

main.cpp

#include <iostream>

namespace N {
    class C {
        public:
            template <class T>
            static void f(int i) {
                (void)i;
                std::cout << __func__ << std::endl
                          << __FUNCTION__ << std::endl
                          << __PRETTY_FUNCTION__ << std::endl;
            }
            template <class T>
            static void f(double f) {
                (void)f;
                std::cout << __PRETTY_FUNCTION__ << std::endl;
            }
    };
}

int main() {
    N::C::f<char>(1);
    N::C::f<void>(1.0);
}

संकलित करें और चलाएं:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

आउटपुट:

f
f
static void N::C::f(int) [with T = char]
static void N::C::f(double) [with T = void]

आप फ़ंक्शन के नामों के साथ स्टैक के निशान में भी दिलचस्पी ले सकते हैं: C या C ++ में प्रिंट कॉल स्टैक

उबंटू 19.04, जीसीसी 8.3.0 में परीक्षण किया गया।

सी ++ 20 std::source_location::function_name

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf C ++ 20 में चला गया, इसलिए हमारे पास इसे करने का एक और तरीका है।

प्रलेखन कहता है:

constexpr const char * function_name () कांस्ट नोसेप्ट;

6 रिटर्न: यदि यह ऑब्जेक्ट किसी फ़ंक्शन के शरीर में स्थिति का प्रतिनिधित्व करता है, तो कार्यान्वयन-परिभाषित NTBS देता है जो फ़ंक्शन नाम के अनुरूप होना चाहिए। अन्यथा, एक खाली स्ट्रिंग लौटाता है।

जहाँ NTBS का अर्थ है "शून्य समाप्त बाइट स्ट्रिंग"।

जब समर्थन जीसीसी के लिए आता है, तो मैं इसे एक कोशिश देता हूं, जीसीसी 9.1.0 के साथ g++-9 -std=c++2aअभी भी इसका समर्थन नहीं करता है।

https://en.cppreference.com/w/cpp/utility/source_location दावा उपयोग इस तरह होंगे:

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

संभावित उत्पादन:

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

इसलिए ध्यान दें कि यह कॉलर जानकारी कैसे लौटाता है, और इसलिए लॉगिंग में उपयोग के लिए एकदम सही है, यह भी देखें: क्या सी ++ फ़ंक्शन के अंदर फ़ंक्शन नाम प्राप्त करने का एक तरीका है?


13

__func__धारा 8.4.1 में C ++ 0x मानक में प्रलेखित है। इस मामले में यह प्रपत्र का एक पूर्वनिर्धारित फ़ंक्शन स्थानीय चर है:

static const char __func__[] = "function-name ";

जहां "फ़ंक्शन नाम" कार्यान्वयन युक्ति है। इसका मतलब यह है कि जब भी आप किसी फ़ंक्शन को घोषित करते हैं, तो कंपाइलर आपके फ़ंक्शन में इस चर को जोड़ देगा। एक ही का सच है __FUNCTION__और __PRETTY_FUNCTION__। उनके बड़े होने के बावजूद, वे मैक्रोज़ नहीं हैं। हालांकि __func__C ++ 0x के लिए एक अतिरिक्त है

g++ -std=c++98 ....

अब भी कोड का उपयोग कर संकलन करेगा __func__

__PRETTY_FUNCTION__और __FUNCTION__यहाँ प्रलेखित रहे हैं http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names__FUNCTION__के लिए सिर्फ एक और नाम है __func__। C __PRETTY_FUNCTION__के समान __func__है, लेकिन C ++ में इसके साथ ही हस्ताक्षर भी शामिल हैं।


__func__C ++ 03 का हिस्सा नहीं है। इसे C ++ 0x में जोड़ा गया है, लेकिन C ++ 0x अभी तक "C ++ मानक" नहीं है, यह अभी भी ड्राफ्ट फॉर्म में है।
जेम्स मैकनेलिस

2
@JamesMcNellis अब शोर को दूर करने के लिए
कमेंट्स को क्लियर करें

7

उन लोगों के लिए, जो आश्चर्य करते हैं कि यह कैसे वी.एस.

MSVC 2015 अपडेट 1, cl.exe संस्करण 19.00.24215.1:

#include <iostream>

template<typename X, typename Y>
struct A
{
  template<typename Z>
  static void f()
  {
    std::cout << "from A::f():" << std::endl
      << __FUNCTION__ << std::endl
      << __func__ << std::endl
      << __FUNCSIG__ << std::endl;
  }
};

void main()
{
  std::cout << "from main():" << std::endl
    << __FUNCTION__ << std::endl
    << __func__ << std::endl
    << __FUNCSIG__ << std::endl << std::endl;

  A<int, float>::f<bool>();
}

उत्पादन:

मुख्य से ():
मुख्य
मुख्य
int __cdecl main (शून्य)

A :: f () से:
एक <int, नाव> :: च
च
शून्य __cdecl A <int, float> :: f <bool> (शून्य)

__PRETTY_FUNCTION__ट्रिगर अघोषित पहचानकर्ता त्रुटि का उपयोग करना , जैसा कि अपेक्षित था।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.