本文共 3679 字,大约阅读时间需要 12 分钟。
____是C99标准里面预定义标识符, 它是一个static char[],
会在每一个使用__func__的函数里隐式定义.下面是ISO9899里的例子
#include <stdio.h>void myfunc(void){ printf("%s/n", __func__); /* ... */}输出: myfunc
据我所知好像只有GCC才支持这个标识符, 其它编绎器厂商要么就没支持要么是扩展为其它. 如VC7里就只有____和GCC里__PRETTY_FUNCTION__.
1,然而这个特性我所感兴趣的是在C++里它能输出什么? 2,它是否能用于构造函数的初始化列表?3,它是否能用于默认参数?4,除用于异常信息或DEBUG信息外还有什么用途?5,应该用标准的还是用扩展的标识符?第一个问题比较好解决,只要写些测试代码就行了.
因为环境的关系我只能用GCC 3.4.2做测试, 在GCC里除__func__还有__FUNCTION__和__PRETTY_FUNCTION__, 前者两个所输出的和上面那个例的的结果一样只有一个函数名, 而后者则比较长细地列出函数的信息.下面是测试在C++里__func__这个特性的输出.
#include <cstdio>#include <cstdlib>#define EXTERN_2
#define _INFO(n) puts(n)
#ifdef STANDARD #define INFO() _INFO(__func__)#endif#ifdef EXTERN_1 #define INFO() _INFO(__FUNCTION__)#endif#ifdef EXTERN_2 #define INFO() _INFO(__PRETTY_FUNCTION__)#endif namespace _{ class Base{ public: virtual ~TestBase(){}}; class Test: public TestBase{ public: Test(){INFO();} template<class T> Test(T){INFO();} Test(int, ...){INFO();} ~Test(){INFO();} static void bar(){INFO();} template<class T> operator T()const{ INFO(); return T(); } friend __stdcall void foo(TestBase& t){INFO();}; struct Widget{};};}int main(){
using namespace _private; using namespace std; { Test t1; Test t2(0, 'a', 'b'); Test const t3=Test(0.); Test::bar(); foo(t1); int i=t3; Test::Widget wg=t3; } system("pause"); return 0;}在默认为__PRETTY_FUNCTION__的输出是:
_private::Test::Test()_private::Test::Test(int, ...)_private::Test::Test(T) [with T = double]static void _private::Test::bar()void _private::foo(_private::TestBase&)_private::Test::operator T() const [with T = int]_private::Test::operator T() const [with T = _private::Test::Widget]virtual _private::Test::~Test()virtual _private::Test::~Test()virtual _private::Test::~Test()Press any key to continue . . . 在GCC里的基本格式是:(static or virtual)namespace::class::function(const or volatile), 而且对template还有附加描述, 但可惜没有对调用规范的描述.第二个问题是"它是否能用于构造函数的初始化列表?"
为什么会这样问呢? 因为据标准说它只是函数体内隐式的定义. 即:struct A{ A():pstr(str){ // err static const char str[]="hello"; } const char* pstr;};但这样是错的, 在初始化列表里的str会被认为是还没声明的. 但我用__func__却没有报错.struct A{ A():pstr(__func__){ // ok static const char str[]="hello"; } const char* pstr;};嗯, 看来它是先于函数体的.(我只用GCC试我还没肯定这个行为是否正确), 因为这个不确定所以我想了第三个问题"它是否能用于默认参数?".
简单的代码试验说明这是不能的:
void foo(char const* pstr=__func__); // err再试试void foo(char const* pstr=__FUNCTION__); // ok竟然编绎通过了, 但pstr=="". (看来这是__func__和__FUNCTION__的区别了)看来它不是能作默认参数的了.嗯, 真的吗?是否会有特例呢? 于是有想了Local Class的情况:
void foo(){
__func__; // 必须在bar的定义前先显式用一次__func__struct A{
void bar(char const* pstr=__func__){ // ok puts(pstr); } };A a;
a.bar(); // 输出的是"foo"而不是"bar"}对于第四个问题我没想到太好的例子, 大概只想到两个:
(base64的编码表)char ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789(int i){ if(i==62)return '+'; if(i==63)return '/'; return __func__[i];}char
(*EnBase64Tab)(int)=&ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789; (COMMAND解释事例)class Command{ virtual void do_execute()=0;public: static void Execute(const char* script[]){ /* foreach(vec) if(script[i]==vec.iter) *iter.do_execute(); */ }protected: static CMDVEC vec;};CMDVEC Command::vec;
class Edit: public Command{
virtual void do_execute(){} static Edit edit; Edit(){Command::vec.push_back(std::make_pair(__func__, this));}};Edit Edit::edit;class Search: public Command{
virtual void do_execute(){} static Search search; Search(){Command::vec.push_back(std::make_pair(__func__, this));}};Search Search::search;就是说若你的应用中函数和它的名子有很大关联的时候可以用上它.
第五个问题是用那个比较好?
我查了一下网上的资料俱称__FUNCTION__只是__func__的一个宏. 但我实际在GCC的预处理器上试过并不是这样. 嗯我油印得一般情况下应该用__func__, 因为它比较短. 而且它是标准里指定的.对于这个新特性我个人理解基本上是这样了, 还需要注意的是在不支持新特性的编绎器上不要用__func__作为变量名, 即使你认为不会用任何新行性, 也应该注意这点.
转载地址:http://dpcdi.baihongyu.com/