重新定义C ++中的C函数 [英] Redefine a C function in C++

查看:252
本文介绍了重新定义C ++中的C函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有函数的C库

#ifdef __cplusplus
extern "C" {
#endif

void exitWithError(const char* func) {
    printf("woopsie in %s", func);
    exit(1);
}

#ifdef __cplusplus
}
#endif

exitWithError仅由库内部的其他C代码调用. C库始终以"C模式"(即通过g++ -x c ...)编译,符合C99,因此不能包含任何C ++代码. (我已经意识到,这使得#ifdef __cplusplus检查完全是多余的,但是哼哼,在这里不相关).

我正在尝试在使用此C库的C ++ 14项目中重新定义exitWithError,以便我可以更改错误的处理方式(请参阅我的

覆盖exit的行为.

extern "C" void exit(int status) {
    throw 1;
}

这很好用,但是具有调用printf的C exitWithError函数.我希望删除该行为,因此C库调用exitWithError时不会打印任何内容.

尝试使用相同的技巧重新定义exitWithError ...

extern "C" void exitWithError(const char* func) {
    throw 1;
}

自然在编译过程中导致duplicate symbol错误.

exit如何重新定义它?有什么方法可以取消定义" exitWithError,以便调用的C ++代码可以重新定义它?

我怀疑在编译供我的C ++项目使用的C库时可以传递一个附加的编译器标志(例如-DSILENCE_FOOL)

void exitWithError(const char* func) {
#ifndef SILENCE_FOOL
    printf("woopsie in %s", func);
#endif
    exit(1);
}

但是我更喜欢一种无需对C代码进行任何修改的方法.

最后,还有一种更明智的方法(重构C库)允许C库的用户挂接"或覆盖exitWithError行为吗?当用户提供不正确的参数时会调用此函数(在我的C ++代码中,我将使用std::invalid_argument覆盖它).

解决方案

在调用C ++代码中,我可以简单地使用来覆盖exit的行为

extern "C" void exit(int status) {
    throw 1; }

exit是C标准库保留的标识符,而void exit(int)是thexitWithErrore C ++标准库保留的函数签名.因此,除非您的目标系统是独立的,否则此定义将违反语言标准.

尝试使用相同的技巧重新定义exitWithError ...

extern "C" void exitWithError(const char* func) {
    throw 1;
}

这违反了一个定义规则.一个功能最多可能有一个定义(有例外,但没有一个对您有帮助).

有什么办法可以取消定义" exitWithError,以便调用的C ++代码可以重新定义它?

标准C或C ++中没有任何内容.

如何退出才能重新定义它?

某些编译器(例如GCC)具有称为弱符号"的功能,该功能使链接程序可以从多个不同的定义中进行选择.您使用的C标准库可能将exit定义为此类弱符号.

您可以使用相同的技术来声明exitWithError的C库定义为弱.但是像其他解决方案一样,这也需要修改库.请注意,在替换exit和替换库函数时,这种方法都是非标准的.


有没有更明智的方法(重构C库)来允许C库的用户钩住"或覆盖exitWithError行为?

您可以通过函数指针引入多态.示例:

// in library (C):
void exitWithErrorDefault(const char* func) {
    printf("woopsie in %s", func);
    exit(1);
}

typedef void errorHandler_f(const char*);
errorHandler_f* exitWithErrorHandler = exitWithErrorDefault;

void exitWithError(const char* func) {
    exitWithErrorHandler(func);
}

// usage (C++)
void exitWithErrorCpp(const char* func) {
    throw 1; // bad
}
int main()
{
    exitWithErrorHandler = exitWithErrorCpp;

抛出从C调用的函数通常是个坏主意.C没有异常,C函数通常也不是异常安全的.导致内存或其他资源泄漏的情况非常普遍.

在这种情况下,调用exitWithError后可能不会尝试释放资源,因为它有望终止该过程.如果您在捕获异常后不尝试继续该过程,那么您可能就不必在意泄漏了.

I have a C library with a function

#ifdef __cplusplus
extern "C" {
#endif

void exitWithError(const char* func) {
    printf("woopsie in %s", func);
    exit(1);
}

#ifdef __cplusplus
}
#endif

exitWithError is exclusively called by other C code internal to the library. The C library is always compiled in "C mode", i.e. via g++ -x c ..., conforming to C99, so cannot feature any C++ code. (I've realised now this makes the #ifdef __cplusplus check completely superfluous, but ho-hum, not relevant here).

I'm seeking to redefine exitWithError in a C++14 project which uses this C library, so that I can change how errors are handled (see my related question). This would change the C library's internal behaviour. I am trying to avoid change to the underlying C library code, but that's not a strict necessity.

It turns out I can, in my calling C++ code, simply override the behaviour of exit with

extern "C" void exit(int status) {
    throw 1;
}

This works great, but features the C exitWithError function calling printf. I wish to remove that behaviour, so nothing is printed when the C library invokes exitWithError.

Trying to redefine exitWithError with the same trick...

extern "C" void exitWithError(const char* func) {
    throw 1;
}

causes a duplicate symbol error during compiling, naturally.

What about exit enabled it to be redefined? Is there any way to "undefine" exitWithError so that the calling C++ code can redefine it?

I suspect I could pass an additional compiler flag (e.g. -DSILENCE_FOOL) when compiling the C library for use in my C++ project, and modify the C library code to

void exitWithError(const char* func) {
#ifndef SILENCE_FOOL
    printf("woopsie in %s", func);
#endif
    exit(1);
}

but I'd prefer a method without any modification to the C code.

And finally, is there a more sensible way (refactoring the C library) to allow users of the C library to "hook in" or override the exitWithError behaviour? It's a function invoked when the user supplies incorrect arguments (in my C++ code, I'll override it with std::invalid_argument).

解决方案

I can, in my calling C++ code, simply override the behaviour of exit with

extern "C" void exit(int status) {
    throw 1; }

exit is an identifier reserved by the C standard library, and void exit(int) is a function signature reserved by thexitWithErrore C++ standard library. So, unless your target system is freestanding, this definition violates the language standard.

Trying to redefine exitWithError with the same trick...

extern "C" void exitWithError(const char* func) {
    throw 1;
}

This violates the one definition rule. There may be at most one definition for a function (exceptions apply, but none that are of help to you).

Is there any way to "undefine" exitWithError so that the calling C++ code can redefine it?

Nothing in standard C or C++.

What about exit enabled it to be redefined?

Some compilers, such as GCC, have a feature called "weak symbol"s, which allows the linker to choose from multiple different definitions. The C standard library that you used probably defines exit as such weak symbol.

You could use the same technique to declare the C library definition of exitWithError weak. But like the other solutions, this also requires modification of the library. Note that this approach is non-standard both when replacing exit and when replacing the library function.


is there a more sensible way (refactoring the C library) to allow users of the C library to "hook in" or override the exitWithError behaviour?

You can introduce polymorphism with a function pointer. Example:

// in library (C):
void exitWithErrorDefault(const char* func) {
    printf("woopsie in %s", func);
    exit(1);
}

typedef void errorHandler_f(const char*);
errorHandler_f* exitWithErrorHandler = exitWithErrorDefault;

void exitWithError(const char* func) {
    exitWithErrorHandler(func);
}

// usage (C++)
void exitWithErrorCpp(const char* func) {
    throw 1; // bad
}
int main()
{
    exitWithErrorHandler = exitWithErrorCpp;

It is generally a bad idea to throw in a function called from C. C has no exceptions and C functions are generally not exception safe. It is quite typical for this to result in memory or other resource leak.

In this particular case, there's probably no attempt to release resources after call to exitWithError anyway since it's expected to terminate the process. If you don't attempt to continue the process after catching the exception, then you probably don't need to care about a leak.

这篇关于重新定义C ++中的C函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆