I would like to make function to be callable (e.g. exposed) to the rest of the library through the macro only, to prevent accidental undesired side effects.
Why? This is because I have a variadic function, which could be called from another variadic function and that way I would like to add NULL sentinel to the call, using macro, thus making access to va_list much easier and prevent undefined behaviour. There are also other handy scenarios, where this could really be helplful.
An example :
test.h
void _func(char *dummy, ...);
//I would like to make sure that rest of the library
//only calls _func through this macro
#define func(dummy, ...) _func(dummy, __VA_ARGS__, NULL)
test.c
//Implementation of the _func function
static void _func(char *dummy, ...) {
//body goes here...
}
main.c
int main(int argc, char *argv[]) {
//This should not be allowed by compiler
_func("dummy", "arg1");
//This should be allowed by compiler, but since definition
//of _func is static in test.c file, compiler is not happy anyway
//LNK2001 unresolved external symbol __func
func("dummy", "arg1");
return 0;
}
I've already tried with #define and #undef compiler directives to somehow force this scenario, but no avail. Is this even possible in C?
You can shadow the function with a macro:
void _func(char *dummy, ...);
#define _func(...) error_use_the_macro_func_instead_of_calling__func_directly
// Always use the macro "func" instead of calling "_func" directly.
#define func(dummy, ...) (_func)(dummy, __VA_ARGS__, NULL)
Notice the parentheses around _func in the macro. This prevents the _func from being recognized as a function-like macro and gives the macro access to the function. If somebody tries to call _func directly, they get
error C2065: 'error_use_the_macro_func_instead_of_calling__func_directly': undeclared identifier
This "macro shadowing" technique has the advantage of being usable in expression contexts:
for (int i = 0; i < 5; func("incrementing i", ++i)) { ... }
or if we change the situation slightly and give _func a return value:
int _func(char *dummy, ...);
#define _func(...) error_use_the_macro_func_instead_of_calling__func_directly
// Always use the macro "func" instead of calling "_func" directly.
#define func(dummy, ...) (_func)(dummy, __VA_ARGS__, NULL)
then this allows you to do things like
int i = func("hello", 2) * func("there", 3);
Maybe you can scope the visibility of the private function? Here's a snippet to illustrate what I mean. Not pretty, but it may work for you(no MSVC to test with here)
#define func(a, b) do { \
extern void private_func(int , int );\
private_func(a, b);\
} while (0)
void foo(void)
{
func(1, 2);
private_func(3, 4);
}
What #Bjorn A. has written in the post above, actually solves my problem as compiler gets angry with the message : '_func': redefinition; different basic types if I try to call _func directly.
Here is the adopted example :
test.h
#define func(dummy, ...) do { \
extern void _func(char *, ...);\
_func(dummy, __VA_ARGS__, NULL);\
} while (0)
test.c
//Implementation of the _func function
//static has to be omitted here, but it doesn't matter
void _func(char *dummy, ...) {
//body goes here...
}
main.c
int main(int argc, char *argv[]) {
//'_func': redefinition; different basic types
//if we try to call _func directly
_func("dummy", "arg1");
//this is ok
func("dummy", "arg1");
func("dummy2", "arg2");
return 0;
}
EDIT : Actually, #Raymond Chen has proposed much better solution with function shadowing - idea is to enclose the function name with parentheses to stop preprocessor from expanding it. More info about that here.
Here is the final (hopefully) solution that works like a charm :
test.h
void _func(char *dummy, ...);
#define _func(...) error_use_the_macro_func_instead_of_calling__func_directly
#define func(dummy, ...) (_func)(dummy, __VA_ARGS__, NULL)
test.c
//Notice the _func is enclosed with parentheses here
void (_func)(char *dummy, ...) {
//body goes here...
}
main.c
int main(int argc, char *argv[]) {
//C2065 'error_use_the_macro_func_instead_of_calling__func_directly': undeclared identifier
//if we try to call _func directly
_func("dummy", "arg1");
//this is ok
func("dummy", "arg1");
func("dummy2", "arg2");
return 0;
}
Many thanks! Cheers!
Is it possible to implement a macro conditional inside a macro function in C. Something like this:
#define fun(x)
#if x==0
fun1;
#else
fun2;
#endif
#define fun1 // do something here
#define fun2 // do something else here
In other words, preprocessor decides which macro to use based on an argument value.
fun(0) // fun1 is "preprocessed"
fun(1) // fun2 is "preprocessed"
I know that this example doesn't work, but I want to know is it possible to make it work somehow?
M.
You cannot use pre-processor conditionals inside a pre-processor directive. Background and workarounds you find for example here: How to use #if inside #define in the C preprocessor? and Is it possible for C preprocessor macros to contain preprocessor directives?
Still, you could do:
#include <stdio.h>
#define CONCAT(i) fun ## i() /* For docs on this see here:
https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html */
#define fun(i) CONCAT(i)
void fun1(void)
{
puts(__FUNCTION__);
}
void fun2(void)
{
puts(__FUNCTION__);
}
int main(void)
{
fun(1);
fun(2);
}
This would result in:
...
int main(void)
{
fun1();
fun2();
}
being passed to the compiler and print:
fun1
fun2
You could obfuscate your code even more by doing for example:
...
#define MYZERO 1
#define MYONE 2
int main(void)
{
fun(MYZERO);
fun(MYONE);
}
resulting in the same code being passed to the compiler.
Lets say I have the following code:
void test(void)
{
#define INIT_DONE
//General initialization stuff
}
void test2(void)
{
#ifndef INIT_DONE
#error "Call function test() first!"
#endif
// Specific initialization stuff
}
And then in main() I call these function as follows:
int main(void)
{
test();
test2();
}
And even though I call test() first, and #define INIT_DONE I still get:
"Call function test() first!"
error on the compiler.
So, how can I achieve, that the function test() has to get called first before any other functions. I could do this with some global boolean variable or something, but I am hoping there is a preprocessor way of doing it. Is there?
The preprocessor runs before your code is handled to the compiler. Everything it does happens before your code runs. The prepocessor has no notion of functions or variables, it just copies input to output and expands macros in between (it actually does some more stuff but that's unimportant). For your code, the preprocessor essentially sees this:
gibberish
#define INIT_DONE
// comment
more gibberish
#ifndef INIT_DONE
#error "Call function test() first!"
#endif
// another comment
even more gibberish
The preprocessor walks through that and first sees #define INIT_DONE, so it defines the macro INIT_DONE to 1; every future appearance of INIT_DONE will be replaced by 1 discarded before the compiler sees the code. Then it sees #ifndef INIT_DONE, but INIT_DONE is already defined so it skips the following bit.
The point is that at no point the preprocessor cares about what is being executed. To do what you want to, use something like this:
#include <assert.h>
/* only visible in the source code form where test() and test2() are defined */
static int init_done = 0;
void test(void)
{
init_done = 1;
/* ... */
}
void test2(void)
{
assert(init_done);
/* ... */
}
There is generally no way to do this in the preprocessor since the preprocessor runs before your program runs. You can also leave these checks out and just emphasize that initialization needs to be done in your documentation. Another approach is to not require initialization by the programmer at all, that is useful depending on the circumstances:
static int init_done = 0;
/* same initialization function as before */
void test(void)
{
init_done = 1;
/* ... */
}
void test2(void)
{
if (!init_done)
test();
/* ... */
}
How to undef a library function to use my version of same function. Notice that I need to include the header file for other functions of same file. So not including is it not an option. Is there any way to use it without changing the name?
You can do the following:
#define function_name function_name_orig
#include <library.h>
#undef function_name
int function_name() {
/* ... */
}
This way the function will not be defined by the header, since it will be replaced by function_name_orig. Implementations of getters or setters in the header file may continue to work - even if they use function_name, since those calls will also be replaced.
For gcc, #undef seems to cut it, so long as you're keeping the same prototype for the function. For example:
#include <stdio.h>
#undef scanf
int scanf(const char * s, ...)
{
printf(s);
return 0;
}
int main()
{
scanf("hello\n");
return 0;
}
This compiles without warnings with -Wall, but if you want scanf to have a prototype of (say) void scanf(void) it will give errors.
I want to define a constant depending on the OS in use.
As such:
#include <stdio.h>
#ifdef _Win32 //Used for system("cls") command
#include <process.h>
#define CLEAR "system(\"cls\")"
#endif
#ifdef __APPLE__
#define CLEAR "system(\"clear\")"
#endif
int main()
{
CLEAR;
}
Xcode gives me an error stating that expression result unused at
#define CLEAR "system(\"clear\") and inside the main function.
I am on a Mac.
Use:
#define CLEAR system("clear")
not
#define CLEAR "system(\"clear\")"
You get the error because your macro call is substituted with:
"system(\"clear\")";
which is a useless expression statement (the expression being the string here) like for example:
0; // valid but pointless
try altering your main function as such:
int main()
{
int rc;
rc = CLEAR;
return rc;
}
You need to catch the return value of the system() call and use it
#define CLEAR system("clear")
and not
#define CLEAR "system(\"clear\")"
The compiler will create a new C code (called pre-processor code) in which will replace the macro name by its content.
so if you define macro in this way:
#define CLEAR "system(\"clear\")"
You will get in the new code (pre-processor code) generated by the Compiler:
int main()
{
"system(\"clear\")";
}
You can see the code generated by the compiler (pre-processor code) with gcc -E