突发奇想:一个函数怎么知道自己是被谁调用?

时间:2021-02-23 09:22:12
目前程序遇到点问题:运行几天后可能会出错,在日志文件中已知道是在哪个函数中出错了。程序中调用这个子函数的地方很多,怎么知道是具体哪一个调用出了问题?
刚开始时想
private function foo(byval value as string,optional byval whoCalls as string="")
,在每一处调用时(或者,只是重点怀疑的地方),把当前函数/过程的名称传给whoCalls,这样在错误日志中就知道了。

但是,调用这个子函数的地方实在是有点多,改的话,太麻烦。
有知道有没有什么方法能方便地知道调用者的信息?
PS.google了一下,好像python有这功能

引用
在一个函数中
def fun():pass
这个函数如何知道是谁调用了它呢?  在C类语言中好像是很难的。但在 Python中却很简单
 
import traceback
def fun():
      s =  traceback.extract_stack()
      print '%s Invoked me!'%s[-2][2]
这个 fun 函数就可以知道是谁调用了它,并打印出来, 我们来试一下:
 
>>> def a():fun()
>>> def b():fun()
>>> a()
a Invoked me!
>>> b()
b Invoked me!
>>>
ok! 怎么应用这个特性呢? 发挥各位的想象力了。

19 个解决方案

#1


函数 调用我(对象类型 水调用我,...) 返回值类型 不定长字符串

    弹出消息框 水调用我。我的名字

结束 函数

#2


我只知道在ide中运行时可以用一个“调用堆栈”的功能查看每个函数或者过程调用的次序。

#3


你是vb6还是.net, .net可以看栈内容

vb6的话我也不知道了,只能改了.装一个MZ-Tool改起来也方便的 

#4


引用 2 楼 sysdzw 的回复:
我只知道在ide中运行时可以用一个“调用堆栈”的功能查看每个函数或者过程调用的次序。

在代码编写阶段我一般用codesmart中的"find reference"功能来查看某个函数在哪些地方被调用,但在运行时就木一点办法(除了传参数进去)

#5


引用 3 楼 clear_zero 的回复:
你是vb6还是.net, .net可以看栈内容

vb6的话我也不知道了,只能改了.装一个MZ-Tool改起来也方便的

又知道了个新工具mz-tool,不知道和codesmart比起来咋样。

#6


   你这是是.NET程序吧?   所有程序都是在栈中调用的。  包括C,汇编。  但是它们只能知道自己这一行汇编指令出错了。C如果编译时支持debug,那么会添加  汇编代码 对应的源码信息进去。  因此,debug 执行一个程序,就能知道对应哪一行挂了。
   
    .net是解释型语言---也许这样说不是很妥当。 它和java一样都是 进程级汇编语言。  它编译的结果不是原生的汇编语言,而是CLR的和机器无关的汇编语言。
     .NET执行时,就是一个虚拟了CPU的虚拟机在执行。
    它的实现是,这样的。每一个函数运行时都对应成为一个 COM对象(.NET是用COM实现的)。 它有一个指针,指向调用它的函数的对象。

    因此,楼主可以实现上述功能。   你可以知道整个调用链。 因为有一个单向的链表存在。 
 --------当然我没看过.NET的CLR的源码,但原理是这样的。

#7


这个好像真没有,不过吗,这个可以有,你写一个可选参数吧  突发奇想:一个函数怎么知道自己是被谁调用?

你的需求还可以这样处理,把这个函数的错误抛给调用者,在调用者继续写日志……


err.Raise err.Number, err.Source, err.Description

#8


Python就是这样实现的。不过Python使用纯C,而不是COM实现。因此代表一个运行中的函数的,不是COM对象,而是一个struct的实例。    

#9


引用楼主 jiashie 的回复:
但是,调用这个子函数的地方实在是有点多,改的话,太麻烦。

用替换中用当前工程、全部替换进行修改并不麻烦。

#10


在替换中选当前工程、全部替换进行修改并不麻烦。

#11


open "srccode" for input as #1

then input strcode,#1

intstr(???)

selelct case keyword

replace.


heheheh

#12


引用 10 楼 chinaboyzyq 的回复:
在替换中选当前工程、全部替换进行修改并不麻烦。

想错了,当没回过。

#13


个人认为,如果是发现某个函数内部出错,那么应该先完善这个函数的错误处理功能,保证这个函数在任何情况下运行都是正常的,这样错误就不会发生在此函数内,而是调用此函数的地方.
个人愚见

#14


楼主你自己的方法挺好的。vb本身没提供这功能,你想主动处理的话肯定不行,必须做好“内应”,修改每个调用的地方吧,觉得应该不是很难,有个代码查找替换的插件的,很好用,还支持正则,批量替换就行了。

VB增强查找插件 Ver 3.3
http://download.csdn.net/source/159976

VB增强搜索插件 v1.5.0.59
http://download.csdn.net/source/549708

个人觉得他低版本好用点。

#15


引用 13 楼 overown 的回复:
个人认为,如果是发现某个函数内部出错,那么应该先完善这个函数的错误处理功能,保证这个函数在任何情况下运行都是正常的,这样错误就不会发生在此函数内,而是调用此函数的地方.
个人愚见

这个函数的错误处理是没问题的,即使出错也不会导致崩溃。
on error goto errHandler
...
foo=0
exit function
errHandler:
   debug.print err.number,err.description
   #if DEBUG_MODE then 
      Stop: Resume
   #end if
   logEvent "in foo()," & err.description & ",Caller=" & whoCalls,True
   foo =-1
另外,这个函数是做数据库操作相关的,传的参数是需要写入的数据,功能很单一。
其实想到这个问题,最开始是因为出现“在异步运行时,操作不能被执行”的错误,与ADO command 线程安全性等有关。就是想看一看出错时是哪几次调用。

#16


引用 15 楼 jiashie 的回复:
on error goto errHandler
...
foo=0


请大姐把你的老本,全部发出来,谢谢~~~~

#17


引用 16 楼 dianyancao 的回复:
引用 15 楼 jiashie 的回复:

on error goto errHandler
...
foo=0


请大姐把你的老本,全部发出来,谢谢~~~~

啥意思?

#18


引用楼主 jiashie 的回复:
目前程序遇到点问题:运行几天后可能会出错,在日志文件中已知道是在哪个函数中出错了。程序中调用这个子函数的地方很多,怎么知道是具体哪一个调用出了问题?
刚开始时想
private function foo(byval value as string,optional byval whoCalls as string="")
,在每一处调用时(或者,只是重点怀疑的地方),把当前函数/过程的名称传……

自定义消息还没有返回过程名简单。

#19


完全可以利用某些编辑器的在当前光标处插入当前行行号功能和键盘宏功能,给调用你这个函数的所有调用处加一个可选字符串参数,内容为调用处的行号。

#1


函数 调用我(对象类型 水调用我,...) 返回值类型 不定长字符串

    弹出消息框 水调用我。我的名字

结束 函数

#2


我只知道在ide中运行时可以用一个“调用堆栈”的功能查看每个函数或者过程调用的次序。

#3


你是vb6还是.net, .net可以看栈内容

vb6的话我也不知道了,只能改了.装一个MZ-Tool改起来也方便的 

#4


引用 2 楼 sysdzw 的回复:
我只知道在ide中运行时可以用一个“调用堆栈”的功能查看每个函数或者过程调用的次序。

在代码编写阶段我一般用codesmart中的"find reference"功能来查看某个函数在哪些地方被调用,但在运行时就木一点办法(除了传参数进去)

#5


引用 3 楼 clear_zero 的回复:
你是vb6还是.net, .net可以看栈内容

vb6的话我也不知道了,只能改了.装一个MZ-Tool改起来也方便的

又知道了个新工具mz-tool,不知道和codesmart比起来咋样。

#6


   你这是是.NET程序吧?   所有程序都是在栈中调用的。  包括C,汇编。  但是它们只能知道自己这一行汇编指令出错了。C如果编译时支持debug,那么会添加  汇编代码 对应的源码信息进去。  因此,debug 执行一个程序,就能知道对应哪一行挂了。
   
    .net是解释型语言---也许这样说不是很妥当。 它和java一样都是 进程级汇编语言。  它编译的结果不是原生的汇编语言,而是CLR的和机器无关的汇编语言。
     .NET执行时,就是一个虚拟了CPU的虚拟机在执行。
    它的实现是,这样的。每一个函数运行时都对应成为一个 COM对象(.NET是用COM实现的)。 它有一个指针,指向调用它的函数的对象。

    因此,楼主可以实现上述功能。   你可以知道整个调用链。 因为有一个单向的链表存在。 
 --------当然我没看过.NET的CLR的源码,但原理是这样的。

#7


这个好像真没有,不过吗,这个可以有,你写一个可选参数吧  突发奇想:一个函数怎么知道自己是被谁调用?

你的需求还可以这样处理,把这个函数的错误抛给调用者,在调用者继续写日志……


err.Raise err.Number, err.Source, err.Description

#8


Python就是这样实现的。不过Python使用纯C,而不是COM实现。因此代表一个运行中的函数的,不是COM对象,而是一个struct的实例。    

#9


引用楼主 jiashie 的回复:
但是,调用这个子函数的地方实在是有点多,改的话,太麻烦。

用替换中用当前工程、全部替换进行修改并不麻烦。

#10


在替换中选当前工程、全部替换进行修改并不麻烦。

#11


open "srccode" for input as #1

then input strcode,#1

intstr(???)

selelct case keyword

replace.


heheheh

#12


引用 10 楼 chinaboyzyq 的回复:
在替换中选当前工程、全部替换进行修改并不麻烦。

想错了,当没回过。

#13


个人认为,如果是发现某个函数内部出错,那么应该先完善这个函数的错误处理功能,保证这个函数在任何情况下运行都是正常的,这样错误就不会发生在此函数内,而是调用此函数的地方.
个人愚见

#14


楼主你自己的方法挺好的。vb本身没提供这功能,你想主动处理的话肯定不行,必须做好“内应”,修改每个调用的地方吧,觉得应该不是很难,有个代码查找替换的插件的,很好用,还支持正则,批量替换就行了。

VB增强查找插件 Ver 3.3
http://download.csdn.net/source/159976

VB增强搜索插件 v1.5.0.59
http://download.csdn.net/source/549708

个人觉得他低版本好用点。

#15


引用 13 楼 overown 的回复:
个人认为,如果是发现某个函数内部出错,那么应该先完善这个函数的错误处理功能,保证这个函数在任何情况下运行都是正常的,这样错误就不会发生在此函数内,而是调用此函数的地方.
个人愚见

这个函数的错误处理是没问题的,即使出错也不会导致崩溃。
on error goto errHandler
...
foo=0
exit function
errHandler:
   debug.print err.number,err.description
   #if DEBUG_MODE then 
      Stop: Resume
   #end if
   logEvent "in foo()," & err.description & ",Caller=" & whoCalls,True
   foo =-1
另外,这个函数是做数据库操作相关的,传的参数是需要写入的数据,功能很单一。
其实想到这个问题,最开始是因为出现“在异步运行时,操作不能被执行”的错误,与ADO command 线程安全性等有关。就是想看一看出错时是哪几次调用。

#16


引用 15 楼 jiashie 的回复:
on error goto errHandler
...
foo=0


请大姐把你的老本,全部发出来,谢谢~~~~

#17


引用 16 楼 dianyancao 的回复:
引用 15 楼 jiashie 的回复:

on error goto errHandler
...
foo=0


请大姐把你的老本,全部发出来,谢谢~~~~

啥意思?

#18


引用楼主 jiashie 的回复:
目前程序遇到点问题:运行几天后可能会出错,在日志文件中已知道是在哪个函数中出错了。程序中调用这个子函数的地方很多,怎么知道是具体哪一个调用出了问题?
刚开始时想
private function foo(byval value as string,optional byval whoCalls as string="")
,在每一处调用时(或者,只是重点怀疑的地方),把当前函数/过程的名称传……

自定义消息还没有返回过程名简单。

#19


完全可以利用某些编辑器的在当前光标处插入当前行行号功能和键盘宏功能,给调用你这个函数的所有调用处加一个可选字符串参数,内容为调用处的行号。

#20