2

I try to use define to replace function call, but I can't find how to replace only the call and not the declaration.

IE:

#define test(); printf("worked\n");

void test()
{
printf("how sad ?\n");
}

int main()
{
test();
}

I can't create my define after the function (project rules)

The problem is : I expected the semicolon after "test()" in the define to replaces only the call, but it replaces also the declaration.

I tried to google and nothing on that, is it really possible ? It's weird that it is not taking the literal expression.

Matthias
  • 4,481
  • 12
  • 45
  • 84
Malorke
  • 53
  • 1
  • 6

4 Answers4

7

A few things to note:

  • #define doesn't require braces () - only use them if you need to handle parameters
  • The syntax doesn't include a semicolon: #define test printf
  • Calling a function like printf() like this (somewhat obscured) can be risky, especially if the caller doesn't expect that their string is used as a format string. Prefer #define test(msg) printf("%s", msg)
  • After a #define test ..., the pre-processor will dumbly replace all instances of test - thus the function declaration will actually read void printf("worked\n"); { ... }

The result should be either:

#include <stdio.h>

#define test(msg) printf("%s\n", msg)

void main(void) {
    test("hello");
}

or:

#include <stdio.h>

void test(const char *msg) {
    printf("%s\n", msg);
}

void main(void) {
    test("hello");
}

If you are trying to use a #define to redirect a function call, then you must use a different symbol... for example:

#include <stdio.h>

/* Comment / uncomment this to change behaviour */
#define REDIRECT_TEST

#ifdef REDIRECT_TEST
#  define my_test(msg) printf("REDIRECTED:%s\n", msg)
#else
#  define my_test      test    
#endif

void test(const char *msg) {
    printf("%s\n", msg);
}

void main(void) {
    my_test("hello");
}
Attie
  • 6,690
  • 2
  • 24
  • 34
  • 1
    Thanks for your answer. Sadly, my project really restrict me and I can't use your solution. I will have to do it manually. – Malorke Aug 16 '18 at 13:38
  • `#define test(); printf("worked\n");` actually means that when you write `test()` it will output `; printf("worked\n");` (notice that extra semicolon)... (or am I wrong?) – Paul Stelian Aug 26 '19 at 14:33
1

printf have a "variadic arguments". Sometimes уou will have a problem if you wont use any solution from that q/a: "How to wrap printf() into a function or macro?"

Some tip like this, for example:

#define MY_PRINTF(...) printf(__VA_ARGS__)

or this:

#define MY_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)
Dennis V
  • 574
  • 7
  • 19
0

you should have the define at a separated header file. and the define shall not include the semicolon. so your code shall look like this:

replace_test.h:

#define test() dummy_test()

test.h:

void test();

test.c:

void test()
{ your test code}

dummy.c:

void dummy_test()
{
 your dummy code here (printf("worked!"); etc.
}

program.c:

//decide which behavior you want, either include replace_test.h or test.h header
#include "replace_test.h"
//#include "test.h"

int main()
{
   test();
}
Eliyahu Machluf
  • 1,251
  • 8
  • 17
  • Can you explain why do you think the answer is completely wrong??? as far as I know, this the common way to use mocks at c with macros. having the define at a header, and using the dummy header as needed. – Eliyahu Machluf Aug 16 '18 at 10:15
  • You did macro with name `test` and then function with the same name `test`. what? – unalignedmemoryaccess Aug 16 '18 at 10:16
  • 1
    it is OK to have a macro and a function with the same name. It would cause problem only if the file test.c or test.h have include to replace_test.h. at the using code (program.c), the user can decide whether to include the real test.h header, and really call the function test(), or to include the replace_test.h header, and have the code which call 'test()' replaced with a call to 'dummy_test()' method. – Eliyahu Machluf Aug 16 '18 at 10:26
  • BTW, regarding mock methods I mentioned before, there is one way doing this with macros, as I mentioned, and another way doing this using function pointers, directing pointers to dummy implementations as needed. – Eliyahu Machluf Aug 16 '18 at 10:29
  • Then explain properly. – unalignedmemoryaccess Aug 16 '18 at 10:30
  • I wrote what each file (header file or source file) shall contain; having title like test.h: and then the code. I think this explains the macro usage here. if you now think the answer is ok, please change its score. – Eliyahu Machluf Aug 16 '18 at 11:13
0

Here is an excerpt from my unit test framework. I believe this does what you want...

void *(*old_calloc)(size_t, size_t) = calloc;
#define calloc unit_calloc
void *unit_calloc(size_t num, size_t size) {
    ...
    void* retv = old_calloc(num, size);
    ...
    return retv;
}

This allows me to redirect a call to calloc() without modifying the code that I am trying to test.

chuckt
  • 203
  • 1
  • 10