-3

I'm trying to rename a "stdio.h" function or at least make an alias for it. I tried:

#include <stdio.h>
#define printf() test()

int main() {
    teste("Hello World!\n");
    return 0;
}

but without success, I've also tried to download the stdio.h source code and edit it but it got too many warnings and it wasn't working as expected.

User
  • 141
  • 1
  • 9
  • 5
    You do it the wrong way. Try `#define teste printf`. Empty brackets will not work as `printf`expects parameters. – Gerhardh Oct 30 '20 at 11:03
  • 8
    @User It is a bad idea to do this. At least you could use a wrapper function for printf. – Vlad from Moscow Oct 30 '20 at 11:03
  • 1
    Moreover, you made a typo in your source code : teste() at calling place versus test() at definition place. – Rachid K. Oct 30 '20 at 11:10
  • 1
    Why do you want to do this? What are you _actually_ trying to achieve? This smells like a typical [XY Problem](http://xyproblem.info/) – Jabberwocky Oct 30 '20 at 11:10
  • @Gerhardh still doesn't work. main.c:(.text+0x1c): undefined reference to `teste' – User Oct 30 '20 at 11:24
  • @VladfromMoscow how I do that? – User Oct 30 '20 at 11:24
  • @Jabberwocky I'm trying to change the functions names to study better with the "algorithm" language(a fictional one that I study on my class to understand the programming). – User Oct 30 '20 at 11:26
  • If you use my define there should not be any reference to `teste` in the compiled object file. Did you add brackets? – Gerhardh Oct 30 '20 at 11:29
  • @Gerhardh yeah, I added brackets. `#define printf test` and `test("Hello World!\n");` – User Oct 30 '20 at 11:33
  • 2
    As I said: Wrong way around. `test` is the alias you want to define – Gerhardh Oct 30 '20 at 11:33
  • @User Just write a function that serves as a wrapper for printf. – Vlad from Moscow Oct 30 '20 at 11:35
  • @Gerhardh working, thx – User Oct 30 '20 at 11:39
  • 3
    @User Instead of using comments to write about changes in your program, you should [edit] your question and **explicitly make clear what you changed**. In this case I suggest to append somenthing like "As recommended by SomeUser I changed the program to (show the new code) and now I get the error (copy&paste the error message)" This makes it easier to see the problems and to give specific advice. You can also answer your question yourself to show the final solution. (The purpose of this site is not only to answer the question for you but also a reference for others that have similar problems.) – Bodo Oct 30 '20 at 11:46
  • @Bodo Yeah, sorry about that I'm new on the website so I dont know how to make questions properly. – User Oct 30 '20 at 11:49
  • @User a wrapper is just a function that "wraps" another one, in your example instead of the `#define` you could do `int test(const char * string){ return printf(string); }` so that you could call it with `test("Hello world!\n");` without redefining the `stdio.h` function (of course this is just an example to illustrate the point, don't get mad at me for not making a variadic function) – John Doe Oct 30 '20 at 12:21

2 Answers2

2

You need to place the macro name first and drop the parenthesis:

#define test printf

Alternatively if you want the parenthesis and arguments:

#define test(...) printf(__VA_ARGS__);

Please note that macros like these only make sense for test code function "mocking". Renaming things just for the sake of it, or in order to create your own "secret macro language" is very bad practice.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • It is also worth noting that if `stdio.h` is included in the translation unit, as the OP shows in their example, then the identifier `printf` is reserved for use as a macro name (section 7.1.3 of the standard). In that case, the macro definitions in this answer and in the question both produce undefined behavior, though the suggestion in this answer might nevertheless manifest that as the wanted result. – John Bollinger Oct 30 '20 at 12:58
  • @john: The fact that `printf` is reserved doesn't mean you can't use it in a macro replacement. `#define test printf` is just fine. – rici Oct 30 '20 at 15:21
0

The idea is to define a macro based on printf(). This is a common way to define home made debug/log services.

There are some traps to avoid:

  1. Do not put a ";" at the end of the macro otherwise you may face problems when the macro is used in "if/else" statements and you put a terminating ";" after the macro:
#define test(...) printf(__VA_ARGS__);

int main(void)
{
  if (1)
    test("message 1\n");
  else
    test("message 2\n");
    
  return 0;
}

The compiler will display an error like: 'else' without a previous 'if'

So, it is preferable to define the macro without any terminating ";" :

#define test(...) printf(__VA_ARGS__)
  1. Force the use of the format string otherwise you would get an error in the following:
#define test(...) printf(__VA_ARGS__)

int main(void)
{
  char *str = "foo%bar";
    
  test(str);

  return 0;
}

The compiler will raise an warning: format not a string literal and no format arguments [-Wformat-security] because there is a "%" in the string.

So, it is preferable to define the macro as:

#define test(format, ...) printf(format, __VA_ARGS__)

int main(void)
{
  char *str = "foo%bar";

  test("%s", str);

  return 0;
}
  1. But if you want to print a string without any format specifiers, like :
#define test(format, ...) printf(format, __VA_ARGS__)

int main(void)
{
  test("A string without format specifiers\n");

  return 0;
}

The compiler will raise an error because the variable part (i.e. __VA_ARGS__) is empty:

error: expected expression before ')' token
6 | #define test(format, ...) printf(format, __VA_ARGS__)

To prevent this, it is possible to use the preprocessor "##" trick (it is a GCC specific extension):

#define test(format, ...) printf(format, ##__VA_ARGS__)

int main(void)
{
  test("A string without format specifiers\n");

  return 0;
}
  1. Of course, as the macro uses a call to a service function (printf()), include the corresponding header file (<stdio.h>) where the macro is defined:
#include <stdio.h>

#define test(format, ...) printf(format, ##__VA_ARGS__)

int main(void)
{
  test("A string without format specifiers\n");

  return 0;
}

As a conclusion, to avoid all the preceding traps and many others while writing macros in C language, I can advise this Best practices for the C language preprocessor

Rachid K.
  • 4,490
  • 3
  • 11
  • 30
  • You should make it clear that `##__VA_ARGS__` is a GCC non-standard extension. – Lundin Nov 02 '20 at 07:29
  • `warning: format not a string literal and no format arguments [-Wformat-security]` Is a _false positive_ and no reason to obfuscate your code with non-standard extensions. It's simply a bad diagnostic from a certain compiler, just ignore it. – Lundin Nov 02 '20 at 07:46
  • @Lundin: Yes the GCC specific extension is pointed out in the link at the end of the answer. The link also specifies that the non standard extensions can be flagged by macros like \_\_GNUC\_\_. In some companies, all the compiler flags detecting any source of weaknesses or bugs, are activated. Even the famous GCC flag -Werror which converts warnings into errors. So, these companies do not tolerate any compiler warning at delivery time. This is part of most of the quality rules because when we deliver products with millions lines of code, the warnings are annoying and may hide serious bugs. – Rachid K. Nov 02 '20 at 08:49
  • @Lundin: I updated my answer to point out the GCC extension for "##" – Rachid K. Nov 02 '20 at 08:55
  • It is very common to have a product running on the field which crashes when some diagnostic mode are activated because they trigger printf-like formatting services which specify incompatible formats and parameters. This is frustrating when it happens. That is why any pre-processing/compiling time check (even non standard ones) which can help to make a robust code at run time are often welcome. – Rachid K. Nov 02 '20 at 09:08