在C语言中以编程的方式获取函数名

(转)用宏获取函数名 c和c++调式 利用宏获得函数名 仅仅为了获取函数名,就在函数体中嵌入硬编码的字符串,这种方法单调乏味还易导致错误,不如看一下怎样使用新的C99特性,在程序运行时获取函数名吧。   对象反射库、调试工具及代码分析器,经常会需要在运行时访问函数的名称,直到不久前,唯一能完成此 项任务并且可移植的方法,是手工在函数体内嵌入一个带有该函数名的硬编码字符串,不必说,这种方法非常单调 阅读详情

  仅仅为了获取函数名,就在函数体中嵌入硬编码的字符串,这种方法单调乏味还易导致错误,不如看一下怎样使用新的C99特性,在程序运行时获取函数名吧。

  对象反射库、调试工具及代码分析器,经常会需要在运行时访问函数的名称,直到不久前,唯一能完成此项任务并且可移植的方法,是手工在函数体内嵌入一个带有该函数名的硬编码字符串,不必说,这种方法非常单调无奇,并且容易导致错误。本文将要演示怎样使用新的C99特性,在运行时获取函数名。

  那么怎样以编程的方式从当前运行的函数中得到函数名呢?

  答案是:使用__FUNCTION__ 及相关宏。

  引出问题

  通常,在调试中最让人心烦的阶段,是不断地检查是否已调用了特定的函数。对此问题的解决方法,一般是添加一个cout或printf()——如果你使用C语言,如下所示:
void myfunc()
{
cout<<"myfunc()"<<endl;
//其他代码
}


  通常在一个典型的工程中,会包含有数千个函数,要在每个函数中都加入一条这样的输出语句,无疑难过上“蜀山”啊,因此,需要有一种机制,可以自动地完成这项操作。

  获取函数名

  作为一个C++程序员,可能经常遇到 __TIME__、__FILE__、__DATE__ 这样的宏,它们会在编译时,分别转换为包含编译时间、处理的转换单元名称及当前时间的字符串。

  在最新的ISO C标准中,如大家所知的C99,加入了另一个有用的、类似宏的表达式__func__,其会报告未修饰过的(也就是未裁剪过的)、正在被访问的函数名。请注意,__func__不是一个宏,因为预处理器对此函数一无所知;相反,它是作为一个隐式声明的常量字符数组实现的:
static const char __func__[] = "function-name";


  在function-name处,为实际的函数名。为激活此特性,某些编译器需要使用特定的编译标志,请查看相应的编译器文档,以获取具体的资料。

  有了它,我们可免去大多数通过手工修改,来显示函数名的苦差事,以上的例子可如下所示进行重写:
void myfunc()
{
cout<<"__FUNCTION__"<<endl;
}


  官方C99标准为此目的定义的__func__标识符,确实值得大家关注,然而,ISO C++却不完全支持所有的C99扩展,因此,大多数的编译器提供商都使用 __FUNCTION__ 取而代之,而 __FUNCTION__ 通常是一个定义为 __func__ 的宏,之所以使用这个名字,是因为它已受到了大多数的广泛支持。

  在Visual Studio 2005中,默认情况下,此特性是激活的,但不能与/EP和/P编译选项同时使用。请注意在IDE环境中,不能识别__func__ ,而要用__FUNCTION__ 代替。

  Comeau的用户也应使用 __FUNCTION__ ,而不是 __func__ 。

  C++ BuilderX的用户则应使用稍稍不同的名字:__FUNC__ 。

  GCC 3.0及更高的版本同时支持 __func__ 和__FUNCTION__ 。

  一旦可自动获取当前函数名,你可以定义一个如下所示显示任何函数名的函数:
void show_name(const char * name)
{
cout<<name<<endl;
}

void myfunc()
{
show_name(__FUNCTION__); //输出:myfunc
}

void foo()
{
show_name(__FUNCTION__); //输出:foo
}


  因为 __FUNCTION__ 会在函数大括号开始之后就立即初始化,所以,foo()及myfunc()函数可在参数列表中安全地使用它,而不用担心重载。

  签名与修饰名

  __FUNCTION__ 特性最初是为C语言设计的,然而,C++程序员也会经常需要有关他们函数的额外信息,在Visual Studio 2005中,还支持另外两种非标准的扩展特性:__FUNCDNAME__ 与 __FUNCSIG__ ,其分别转译为一个函数的修饰名与签名。函数的修饰名非常有用,例如,在你想要检查两个编译器是否共享同样的ABI时,就可派得上用场,另外,它还能帮助你破解那些含义模糊的链接错误,甚至还可用它从一个DLL中调用另一个用C++链接的函数。在下例中,show_name()报告了函数的修饰名:
void myfunc()
{
show_name(__FUNCDNAME__); //输出:?myfunc@@YAXXZ
}


  一个函数的签名由函数名、参数列表、返回类型、内含的命名空间组成。如果它是一个成员函数,它的类名和const/volatile限定符也将是签名的一部分。以下的代码演示了一个独立的函数与一个const成员函数签名间的不同之处,两个函数的名称、返回类型、参数完全相同:
void myfunc()
{
show_name(__FUNCSIG__); // void __cdecl myfunc(void)
}

struct S
{
void myfunc() const
{
show_name(__FUNCSIG__); //void __thiscall S::myfunc(void) const
}
};

相关的预编译宏还有
__DATE__
__FILE__
__LINE__
__STDC__
__STDC_HOSTED__ [C99]
__STDC_VERSION__ [C95]
__STDC_IEC_559__ [C99]
__STDC_IEC_559_COMPLEX__ [C99]
__STDC_ISO_10646__ [C99]

__FUNCTION__
__TIMESTAMP__

GCC:3种宏获取函数名;__func__ 而且需要注意,这里是const的字符串指针变量。所以作为参数传入的时候,需要注意参数类型。后续在命令行定义的__FILE__会覆盖编译器定义的__FILE__.如果在命令行使用-D参数,又重新定义这个文件,就会报一个警告。在C++里,使用这些宏定义,是mangle之前的函数名称。 阅读详情

相关推荐

获得上级调用的函数名

C#获取调用当前方法的方法名代码如下: using System; using System.Diagnostics; namespace StackTraceTest { /**//// /// Class1 的摘要说明。 /// class Class1 { /**//// /// 应用程序的主入口点。 ///

liuyuehui的专栏 2905

在C / C ++中,__FUNCTION__,__func__、__PRETTY_FUNCTION__和__FUNCSIG__的作用及区别

官方C99标准为此目的定义的__func__标识符,确实值得大家关注,然而,ISO C++却不完全支持所有的C99扩展,因此,大多数的编译器提供商都使用 __FUNCTION__ 取而代之,而 __FUNCTION__ 通常是一个定义为 __func__ 的宏,之所以使用这个名字,是因为它已受到了大多数的广泛支持。在最新的ISO C标准中,如大家所知的C99,加入了另一个有用的、类似宏的表达式__func__,其会报告未修饰过的(也就是未裁剪过的)、正在被访问的函数名。该宏用于获取当前函数的名称。

qq_27898413的博客 5084

OnePlus救砖指南:线刷包与OTA全量包实战解析

本文详细解析了OnePlus手机救砖的两种核心方法:线刷包与OTA全量包。针对手机变砖的不同状况(如黑屏、能进Recovery等),文章提供了清晰的判断标准和对应的实战操作指南。重点阐述了线刷包作为终极救砖手段的底层原理与详细步骤,并对比了OTA全量包作为温和修复方案的使用场景与卡刷流程,旨在帮助用户安全、有效地恢复手机系统。

weixin_28312391的博客 1315

深入理解C++11之__FUNCTION__预定义标识符

C++11支持__FUNCTION__预定义标识符,基本功能是实现返回所在函数的名字,这样做的一个好处是有利于调试程序。例如

《致青春》——云梦泽 1903

使用Simulink设计并实现一个可调谐的二阶IIR陷波滤波器,实时去除音频中的工频噪声

《基于Simulink的音频陷波滤波器设计与实现》摘要:本文详细介绍了使用Simulink设计陷波滤波器去除音频工频噪声(如50Hz)的方法。核心内容包括:1)二阶IIR陷波滤波器的原理与传递函数;2)Simulink实现步骤(音频系统搭建、滤波器设计、频率跟踪);3)性能分析(频谱对比、时域波形、听觉测试)。通过精准消除特定频率干扰,同时保留语音信号(200Hz-4kHz),有效提升信噪比(>20dB)。文章还探讨了多陷波级联、自适应算法等高级技巧,为音频处理、语音通信等应用提供实用解决方案。

amy_mhd的博客 152

OpenStack详解、排错、经验总结

第1章 Openstack简介 1.1 计算(Compute):Nova。 一套控制器,用于为单个用户或使用群组管理虚拟机实例的整个生命周期,根据用户需求来提供虚拟服务。负责虚拟机创建、开机、关机、挂起、暂停、调整、迁移、重启、销毁等操作,配置CPU、内存等信息规格。自Austin版本集成到项目中。 1.2 对象存储(Object Storage):Swift。 一套用于在大规模可扩展系统中通过内置冗余及高容错机制实现对象存储的系统,允许进行存储或者检索文件。可为Glance提供镜像存储,为Cinder提供

weixin_40548182的博客 1974

__FUNCTION__ 在C语言中以编程的方式获取函数名(VC6.0不支持)

仅仅为了获取函数名,就在函数体中嵌入硬编码的字符串,这种方法单调乏味还易导致错误,不如看一下怎样使用新的C99特性,在程序运行时获取函数名吧。   对象反射库、调试工具及代码分析器,经常会需要在运行时访问函数的名称,直到不久前,唯一能完成此项任务并且可移植的方法,是手工在函数体内嵌入一个带有该函数名的硬编码字符串,不必说,这种方法非常单调无奇,并且轻易导致错误。本文将要演示怎样使用新的C99特

agan4014的专栏 3825

基于MATLAB自动发电控制(AGC)仿真系统的设计与实现:电力系统频率稳定与功率平衡的深入解析

自动发电控制(AGC)是电力系统运行中的一个关键功能,其主要任务是通过自动调节发电机组的输出功率,使得电网中的频率稳定在规定范围内,并维持发电与负荷的动态平衡。当电力负荷发生变化时,AGC会立即响应,调整发电机的功率输出,以避免电网频率的剧烈波动。维持系统频率稳定:电网频率通常应维持在标准值(例如50Hz或60Hz)附近。当负荷波动或电力需求突然变化时,AGC通过调节发电机输出,确保频率不发生过大的偏离。实现区域内的功率平衡。

qq_38334677的博客 1106

在C语言中以编程的方式获取函数名http://www.newasp.net/tech/program/23098.html

  仅仅为了获取函数名,就在函数体中嵌入硬编码的字符串,这种方法单调乏味还易导致错误,不如看一下怎样使用新的C99特性,在程序运行时获取函数名吧。   对象反射库、调试工具及代码分析器,经常会需要在运行时访问函数的名称,直到不久前,唯一能完成此项任务并且可移植的方法,是手工在函数体内嵌入一个带有该函数名的硬编码字符串,不必说,这种方法非常单调无奇,并且容易导致错误。本文将要演示怎样使用新的C99特

xu的blog 1669

uniapp - HBuilder提示adb: failed to install X Failure [INSTALL_ARSE_FAILED_NOT_APK:X(安装HBuilder调试基座失败)

安装HBuilderX调试基座失败,uniapp APP运行到手机adb: failed to install,Uniapp提示adb,uniapp ios 真机调试报错 uniapp安卓调试,Uniapp安装不了基座,手动安装基座,正在安装手机端HBuilder调试基座,点击运行到手机报错信息:基座无法正常安装,Uniapp-安装HBuilder调试基座失败解决方案,解决 HBuilderX 安卓基座安装失败的问题,显示adb报错,UniApp苹果真机运行调试(自定义基座,版本更新后/没有基座打开失败)如

🏆 前端领域优质创作者 8061

【GEOS-Chem模拟教程第二期下】全球生物质燃烧 GFAS 数据配置

本博客详细介绍全球生物质燃烧 GFAS 数据下载及在 GEOS-CHEM 模型中的配置

WW、forever的博客 1394

c语言中常常用到的宏

__FILE__                      //编译的文件     __LINE__                     //代码所在的行     __FUNCTION__          //代码所在的函数   这三个宏,一般的编译器都认识。 3.7.1 Standard Predefined Macros The standard predefined m

virlhs的专栏 1576

phpMyAdmin | mysqli::real_connect(): (HY000/2002): No such file or directory

第一次安装宝塔mysql服务是默认关闭的,需要手动打开,打开服务再次进入phpMyAdmin发现可以进入了。

吻等离子的博客 2870

C语言软件怎么运行C51文件,keil c51中C程序的启动过程

函数的入口地址,如何调用汇编函数,c和汇编的混合编程/*******************************************************************/c函数的函数名是一个指向函数的指针常量,它的值就是函数的入口地址。从汇编程序上看,函数名也是该汇编函数代码段的入口地址标号。调用汇编函数就是调用汇编函数的入口地址标号,但是要注意c函数名和汇编函数标号之间的转换...

weixin_36040584的博客 718

vscode的launch:program ‘‘ does not exist

如图 一般是由于launch.json文件没有配置好的缘故。在右下角的ADD configuration如选第二个登录: 看到program这一栏,这一栏很重要,一般是选择你CMakelist,编译出来的可执行文件 看我CMakelist, 我生成的可执行文件是test_,所以路径可以这样输入: 我在之前cmake的时候已经有了test_这个文件了 然后就可以运...

狂小虎/Anthony Dave的博客 KuangXiaoHu's Blogs 5万+

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

C语言调用C++ 库方式

C语言调用C++ 库方式

qq_31057589的博客 8482

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

C语言-函数指针与函数名的区别

记得大学时老师曾说函数的函数名是函数的入口的指针,之前看block通过clang编译生成的C代码发现很多函数指针,于是想了解函数指针与函数名有什么区别?以及函数指针一般都有些什么作用。 函数指针与函数名的区别 首先先定义一函数以及一个指向盖函数的函数指针,并分别对他们进行调用。 #include void fun(int x); int main(int argc, const char

树深时见鹿 1万+

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

c语言中函数名可不可以由用户命名,C语言中变量名及函数名的命名规则与驼峰命名法...

在程序设计中,变量名、函数名、数组名等统称为标识 符。简单地说,标识符就是一个名字。除库函数的函数名由系统定义外,其余都由用户自定义。C语言规定,标识符只能由字母(a~z,A~Z)、数字 (0~9)、下划线(_)组成,并且标识符的第一个字符必须是字母或下划线,不能以数字开头。C语言不限制标识符的长度,但它受各种C语言编译器的限制, 同时也受到具体机器的限制。例如,在某编译器中规定标识符前8位有效,...

weixin_36257799的博客 4248
上一篇: dump call stack 的实现
下一篇: 利用钩子实现菜单阴影效果
ShenRui
博客等级 码龄20年 63粉丝 36原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值