简体   繁体   English

c ++测试缺少的回调函数

[英]c++ Testing for a missing callback function

EDIT: added backquotes to callback template. 编辑:添加反引号到回调模板。 The interface was reading the asterisks as markdown indicators, not just as asterisks! 界面正在读取星号作为降价指示符,而不仅仅是星号!

In a Windows DLL/Linux SO I am writing, I give the user app a way to register a callback function. 在我正在编写的Windows DLL / Linux中,我为用户应用程序提供了一种注册回调函数的方法。 Works great. 效果很好。 The callback prototype looks like (void)(*callback)(void*); 回调原型看起来像(void)(*callback)(void*);

I was having a fit of paranoia while writing the docs and realized, I have no really good way to know if the registered address is valid. 我在编写文档时遇到了偏执狂,并且意识到,我没有真正好的方法来知道注册地址是否有效。 The only feedback is either a crash or call the callback inside a try/catch. 唯一的反馈是崩溃或在try / catch中调用回调。

I have no idea what exception would be thrown if the callback did not exist and who-knows-what executed. 我不知道如果回调不存在并且执行了谁知道的操作会抛出什么异常。 NOt even really sure that the call to "nowhere" could recover itself enough to generate the exception instead of a crash. 甚至没有真正确定对“ nowhere”的调用可以自我恢复到足以产生异常而不是崩溃的程度。

Yes, I know it's the user's problem. 是的,我知道这是用户的问题。 Just trying to be thoughtful and maybe help the user understand his bug. 只是要考虑周到,并可能帮助用户理解他的错误。

So, what exception would this throw? 那么,这会抛出什么异常? Windows and Linux answers please if they differ. 如果Windows和Linux不同,请回答。

Or, is there a better way to approach this without having to use an exception catch to detect the missing function? 或者,是否有更好的方法来解决此问题,而不必使用异常捕获来检测缺少的功能?

There's no way to recover. 无法恢复。 Similarly, you cannot recover if the callback contains a line like *(int*)(0x1234) = 5; 同样,如果回调包含*(int*)(0x1234) = 5;这样的行,则无法恢复*(int*)(0x1234) = 5; . Just live with it. 只是忍受它。

As a C++ library developer, you're not in the business of making sure that nothing ever crashes. 作为C ++库开发人员,您无需确保不会崩溃。 You merely provide code that does what it promises when used the way you document. 您只提供可以按照您的文档方式使用的代码。

A bit off-topic, but callbacks in the form of void(*)() , ie taking 0 arguments, are less than useful. 有点离题,但是以void(*)()的形式进行回调void(*)()即接受0个参数)的用处不大。 A useful C-style callback accepts a user specified argument, so that the user can find the state corresponding to the callback. 有用的C样式回调函数接受用户指定的参数,以便用户可以找到与该回调函数相对应的状态。 Eg: 例如:

typedef void callback_fn(void* user_arg);

callback_id register_callback(callback_fn* callback, void* user_arg);
void unregister_callback(callback_id);

Without user_arg the user of your callback will be forced to use a global variable to store state corresponding to the callback function. 如果没有user_arg则回调的用户将被迫使用全局变量来存储与回调函数相对应的状态。

The situation you describe is rather unlikely. 您描述的情况不太可能发生。 I have never seen such handling anywhere. 我从未在任何地方看到过这样的处理方式。 The program would just crash and ruin its user. 该程序将崩溃并破坏其用户。

But your concern is valid, because the failure root cause (assigning wrong address) and its manifestation (call to invalid address) can be so far away from each other that it could be very hard to identify it. 但是您的担心是正确的,因为失败的根本原因(分配错误的地址)和其表现形式(调用无效的地址)可能相距太远,以致于很难识别它。

All I could advise here is to "fail fast and loud". 我在这里只能建议“大声失败”。 For instance, you could do test call of the callback whenever it is assigned. 例如,您可以在分配回调时进行测试。 This will still lead to crash, but now in the stack trace user will see where it all started from. 这仍然会导致崩溃,但是现在,在堆栈跟踪中,用户将看到这一切都是从哪里开始的。

Again, this is not something an ordinary library user would expect... 再次,这不是普通库用户所期望的。

As I answered here: 正如我在这里回答的那样:

How to test if an instance is corrupted? 如何测试实例是否损坏? (completely different type of question, but same applies) (完全不同的问题类型,但同样适用)

If the pointer is "not recognisable NULL or similar", then there is no way, in code, to tell if it's valid or not. 如果指针是“不可识别的NULL或类似的字符”,则在代码中没有办法判断它是否有效。

You also can't use try/catch to capture the failure, as "failure to execute the code" does not result in a throw. 您也不能使用try/catch捕获失败,因为“执行代码失败”不会导致抛出异常。

Since this a "programmer error", I don't believe it's a big issue. 由于这是“程序员错误”,因此我认为这不是大问题。 Programmers can do what they like with their own code anyway, so whatever mechanism you add, it's going to be possible to circumvent in some way or another. 程序员无论如何都可以用自己的代码来完成自己喜欢的事情,因此,无论添加什么机制,都将有可能以某种方式规避。

As others have said, there's no way to check, but... Is it really necessary? 正如其他人所说,无法检查,但是...真的有必要吗? I'm all in favor of defensive programming, but the only way you can possibly get a pointer to a function (other than a null pointer) is by taking the address of a function. 我全都赞成防御性编程,但是您可能获得指向函数的指针(空指针除外)的唯一方法是获取函数的地址。 Some compilers do allow explicitly converting a pointer to an object to a pointer to function, despite the fact that the standard requires a diagnostic in such cases. 尽管标准在这种情况下需要诊断,但某些编译器的确允许将对象的指针显式转换为函数的指针。 But even then, the client code needs an explicit cast to screw up. 但是即使这样,客户端代码也需要显式转换才能解决。 And unlike objects, functions life through out the lifetime of the program, so you cannot have a problem with a dangling pointer—a pointer which was once valid, but isn't any more. 与对象不同,函数在程序的整个生命周期中一直存在,因此悬空的指针不会有问题-指针曾经是有效的,但现在不再有效。 There is, in fact, practically no way to get an invalid pointer to a function except intentionally (the only way that occurs to me is if the unload a DLL with the function), and if someone intentionally wants to screw up, there's no way you'll be able to prevent it. 实际上,除了故意地以外,几乎没有其他方法可以获取指向函数的无效指针(对我而言,唯一的方法是使用该函数卸载DLL),并且如果有人故意搞砸了,那也没有办法。您将能够预防这种情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM