重新定义C ++中的C函数 [英] Redefine a C function in 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库的用户钩住"或覆盖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屋!