__func__标识符

来源:互联网 发布:smc软件 编辑:程序博客网 时间:2024/04/27 20:00

 __func__是C99标准里面预定义标识符, 它是一个static const char[],
会在每一个使用__func__的函数里隐式定义.

下面是ISO9899里的例子
#include <stdio.h>
void myfunc(void)
{
     printf("%s/n", __func__);
     /* ... */
}

输出: myfunc

 据我所知好像只有GCC才支持这个标识符, 其它编绎器厂商要么就没支持要么是扩展为其它. 如VC7里就只有__FUNCTION__和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 _private{
class TestBase{
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__作为变量名, 即使你认为不会用任何新行性, 也应该注意这点.