I'm trying to define various functions with the same name as C stdio to prevent unwanted usage. I encountered an odd situation where the technique works on some functions, but not others. I cannot explain why A::fn
calls the stdio version of vfprintf
instead of the function definition in the A
namespace.
#include <stdio.h>
#include <stdarg.h>
namespace A {
template <typename... Ts>
void putchar(int ch) {
static_assert(sizeof...(Ts) == -1);
}
template <typename... Ts>
void vfprintf(FILE* file, const char* fmt, va_list vlist) {
static_assert(sizeof...(Ts) == -1);
}
void fn(const char* fmt, ...)
{
putchar('A'); // fails to compile (as expected)
va_list vlist;
va_start(vlist, fmt);
vfprintf(stdout, "Hello!\n", vlist); // does not fail (not expected)
va_end(vlist);
}
}
int main()
{
A::fn("hello");
return 0;
}
P.S. Happy to hear comments indicating that there is a better way to restrict C-style I/O (maybe clang-tidy).
CodePudding user response:
Replacing standard library routines is UB (citation to follow). See examples here and here for the kind of trouble this can cause.
Edit: OK, here's the promised citation:
The C standard library reserves the following kinds of names:
...
names with external linkage
...
If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by [library], its behavior is undefined.
But, as discussed in the comments, I'm not sure whether you're doing this in a permitted context or not (although, on reflection, I don't think you are), so I'm going to change tack.
There is, in fact, a very simple way to do what you want. You can do this with #pragma GCC poison
. So, taking your example, all you need is:
#pragma GCC poison putchar vfprintf
and you're done. clang also supports this pragma.
Hats, rabbits, we can do it all :) (on good days)