Usage of #if defined for function definition - c

I need to know if the usage of #if defined is correct and know the possible cons of using it this way.
#if defined TEST
int foo()
{
return 0;
}
int foo1()
{
return 0;
}
#else
int foo()
{
return 1;
}
int foo1()
{
return 1;
}
#endif
EDIT:
I am trying to use this code for two different platforms I am working on.

It is syntactically correct.
The primary disadvantage of that way of organizing it is that you repeat the definitions of the functions for both the test and non-test cases. What is not possible to tell from a carefully minimized example is how much of a problem that will be. The other way to organize it, assuming that the current return statements are surrogates for a more substantial block of code (at least in one of the two cases) would be:
int foo(void)
{
#if defined TEST
return 0;
#else
return 1;
#endif /* TEST */
}
int foo1(void)
{
#if defined TEST
return 0;
#else
return 1;
#endif /* TEST */
}
For these exact functions, you could do:
#ifdef TEST
#define RETVAL 0
#else
#define RETVAL 1
#endif /* TEST */
int foo(void)
{
return RETVAL;
}
int foo1(void)
{
return RETVAL;
}
However, your real functions are unlikely to be quite so simple, so this doesn't translate well.
The general goal is to avoid repetition, and to avoid conditional compilation showing in your functions.

the only problem I can think of is redundancy and for a serious project it's a really serious isuue. you should keep code duplication as small as possible, this is another way to do this with less code duplication:
int foo()
{
#if defined TEST
return 0;
#else
return 1;
#endif
}
int foo1()
{
#if defined TEST
return 0;
#else
return 1;
#endif
}

You could create a multiplatform library, putting the specific platform code in another specific platform library. That way, your multiplatform library can use the right specific library using #if directives. In other words, you will isolate specific platform code.

Related

Functions parameters using macro

I wanted to know if it was contraindicated to define functions parameters using a macro, knowing they could be variable. Does it break a coding convention ?
example:
#ifdef PREVIOUSLY_DEFINED_MACRO
# define PARAMETERS int a, long b
#else
# define PARAMETERS int a
#endif
void my_func(PARAMETERS)
{
...
}
Thanks !
The code is completely valid but, it's not a good coding practice.
Let's assume the following code snippet:
#ifdef PREV_DEFINED
#define ARGS int x, int y
#else
#define ARGS int x
#endif
#include <stdio.h>
// #define PREV_DEFINED
int func(ARGS) {
// In this context, only 'x' is available
// set by the macro
return (x + y); // ERROR, 'y' is undefined
// You need to make a different code, specifically for
// #ifdef PREV_DEFINED and #else
}
To solve this, you need to make two or more different functions within those #ifdef and #endif flags whose usage is controlled by the PREV_DEFINED macro that depends on how many parameters could be variadic. Eventually, this will make the code look worse.

Is there a way to avoid code duplication in multiple similar functions?

I am writing a family of functions which are to be embedded in a small micro-controller operating at very near real time, so every clock cycle counts. The functions are almost identical.
The only way that I can see to do this without duplicating vast chunks of code is to use the really ugly and frowned upon method of declaring the code in an include file which is then intentionally included multiple times.
The following works to demonstrate the concept:
// func.inc
// The absence of an include guard is intentional, as each time this file gets included
// the output will be different
void FUNC(int x)
{
/* SNIP - lots and lots of code that is duplicated between
variant A and B (and more) of the function
for ( ... 4096 )
{
for( lots more nested loops)
{
*/
// IMPORTANT - I do not want to call functions here as it is
// in a tight loop withconsecutive memory accesses of
// different sizes of strided sparse arrays
#ifdef A
printf("A %d\n", x);
#endif
#ifdef B
printf("B %d\n", x);
#endif
/*
}
}
*/
// main.c
#include <stdio.h>
#define FUNC func_A
#define A
#include "func.inc"
#undef A
#undef FUNC
#define FUNC func_B
#define B
#include "func.inc"
#undef B
#undef FUNC
#define FUNC func_AB
#define A
#define B
#include "func.inc"
int main()
{
func_A(10);
func_B(20);
func_AB(30);
printf("Done\n");
return 0;
}
My problem is that whilst this works, it looks hideous, and might be very confusing to someone else trying to understand it. Using a pointer to a function is too inefficient to be a viable option in this case.
Is there a solution that anyone can suggest without simply duplicating several slightly different versions of the same function?
It's not really clear what's pseudo code and real code here, but overall you should not use #define + #undef + #include for the purpose of different code generation. (You could do it with "X macros" though as a last resort. Not an ideal solution but better than this.)
The solution to " IMPORTANT - I do not want to call functions here" is to call functions.
Function inlining has been a thing for some 30 years and 20 years ago C got explicit language support for it. And nowadays compilers are much better than programmers to determine what to inline. I'll make an example with explicit inline just to demonstrate that calling functions does not affect performance, if done correctly.
With traditional C, you would do something like this:
#include <stdio.h>
static inline void SNIP (void)
{
puts(__func__);
}
static inline void A_stuff (int val)
{
printf("%s %d\n", __func__, val);
}
static inline void B_stuff (int val)
{
printf("%s %d\n", __func__, val);
}
typedef enum { A=1, B=2 } AB_t;
void func(AB_t ab, int val)
{
SNIP();
if(ab & A)
A_stuff(val);
if(ab & B)
B_stuff(val);
}
int main()
{
func(A, 10);
func(B, 20);
func(A|B, 30);
printf("Done\n");
return 0;
}
That's the sane solution. The only functions that are actually called in the generated machine code are func and the printing functions.
Alternatively, you could have done code generation with "X macros" too - these exist solely for the purpose of avoiding code repetition, at the expense of readability. Wouldn't really recommend it here, but I'll include an example for completeness:
#include <stdio.h>
#define FUNC_LIST \
X(A, 10) \
X(B, 20) \
X(AB, 30) \
static inline void SNIP (void)
{
puts(__func__);
}
static inline void A_stuff (int val)
{
printf("%s %d\n", __func__, val);
}
static inline void B_stuff (int val)
{
printf("%s %d\n", __func__, val);
}
static inline void AB_stuff (int val)
{
A_stuff(val);
B_stuff(val);
}
#define X(opt, val) void func_##opt (int x) { SNIP(); opt##_stuff(x); }
FUNC_LIST
#undef X
int main()
{
#define X(opt, val) func_##opt(val),
FUNC_LIST
#undef X
printf("Done\n");
return 0;
}
This is quite unreadable just like the original code, except "X macros" are something of a de facto standard for icky macro tricks to avoid code repetition.
This creates multiple functions just like a C++ template, so it isn't ideal for that reason as well.
Edit: The question was originally tagged with C++, hence the answer.
Make a template!
// func.hpp
#ifndef FUNCITON_HPP
#define FUNCITON_HPP
enum Specifier : int {
A = 1 << 0,
B = 1 << 1,
};
#include <cstdio>
template <auto sp>
void foo(int x)
{
/* SNIP - lots and lots of code that is duplicated between
variant A and B (and more) of the function
for ( ... 4096 )
{
for( lots more nested loops)
{
*/
// IMPORTANT - I do not want to call functions here as it is
// in a tight loop withconsecutive memory accesses of
// different sizes of strided sparse arrays
if constexpr (static_cast<bool>(sp & Specifier::A)) {
std::printf("A %d\n", x);
}
if constexpr (static_cast<bool>(sp & Specifier::B)) {
std::printf("B %d\n", x);
}
}
#endif //!FUNCITON_HPP
Then
// func.cpp
#include "func.hpp"
auto constexpr func_a = foo<Specifier::A>; // Could also use a #define
auto constexpr func_b = foo<Specifier::B>;
auto constexpr func_ab = foo<Specifier::A | Specifier::B>;
int main()
{
func_a(1);
func_b(1);
func_ab(1);
}

C multiple function definitions using preprocessor

I have a C file with a function definition.
#ifdef SOMEFEATURE
myfunction_withfeature()
#else
myfunction_withoutfeature()
#endif
{
do_something;
#ifdef SOMEFEATURE
do_one_way;
#else
do_another_way;
#endif
do_something_else;
}
If I define SOMEFEATURE in a header or in the Makefile I get one version, if not I get another version. What I need is two versions. I understand I can copy and paste the code and define/undefine the symbol but that seems messy. Is there a way I can have both functions defined without duplicating code?
One possibility is to put just the function in a separate file, let's say justmyfunction.c:
#ifdef SOMEFEATURE
void myfunction_withfeature()
#else
void myfunction_withoutfeature()
#endif
{
printf("Always doing this.\n");
#ifdef SOMEFEATURE
printf("Doing it one way, with the feature.\n");
#else
printf("Doing it another way, without the feature.\n");
#endif
printf("Always doing this too.\n");
}
And then #include it in the file with the other functions:
#include <stdio.h>
#include "justmyfunction.c"
#define SOMEFEATURE
#include "justmyfunction.c"
int main(void) {
printf("Doing it twice...\n");
myfunction_withfeature();
myfunction_withoutfeature();
printf("Done.\n");
return 0;
}
Or you can do horrible things with macros:
#include <stdio.h>
#define DEFINE_MYFUNCTION(function_name, special_code) \
void function_name() \
{ \
printf("Always doing this.\n"); \
\
special_code \
\
printf("Always doing this too.\n"); \
}
DEFINE_MYFUNCTION(myfunction_withfeature, printf("Doing it one way, with the feature.\n");)
DEFINE_MYFUNCTION(myfunction_withoutfeature, printf("Doing it another way, without the feature.\n");)
int main(void) {
printf("Doing it twice...\n");
myfunction_withfeature();
myfunction_withoutfeature();
printf("Done.\n");
return 0;
}
Or generate the code for the different functions, using a script.
Well, you can compile your code twice with:
cc -DSOMEFEATURE x.c -o x1.o
cc -x.c -o x2.o
and then link those objectfiles. Keep in mind, that you will need to make sure that the other functions that do not have "two versions" will be duplicated and linker won't like it. So you will need to put ifdefs around them, or to make sure that your file contains only functions with "ifdef SOMEFEATURE".
In general, I think that this is a bad design decision and one should avoid it if possible.
#Thomas Padron-McCarth has the right way to deal if you want to just use the pre-processor, in my opinion. If things get too complicated for that, then you'll need to switch to some other kind of templating or code-generation system. I've personally used perl scripts that spit out C or C++ code, and then there's Cog, which uses python to replace sections of code on the fly.
You could:
Move common code into subroutines (functions).
Pass a flag as an argument: eg:
myfunction_withfeature() { myfunction_common(true); }
my_function_withfeature()
{
my_common_function(1);
}
my_function_withoutfeature()
{
my_common_function(0);
}
my_common_function(int feature)
{
do_something;
if (feature == 1) {
do_one_way;
}
else {
do_another_way;
}
do_something_else;
}

How do I implement access specifiers in C?

I was trying to implement access specifier (not sure if that is called access specifier)
The purpose is to make a function (func2) callable only at one place(inside func1).
int func1 ()
{
// Make func2 callable only here`
#define FUNC2_CALLABLE
func2();
#undef FUNC2_CALLABLE
}
#ifdef FUNC2_CALLABLE
int func2 ()
{
return 1;
}
#endif // FUNC2_CALLABLE
func2 should be callable only from func1 and not from any other place in the code.
Does the above code serve the purpose ? Any alternative suggestions
< Edit 1 >
How about doing it this way
int func2()
{
#ifdef FUNC2_CALLABLE
return 1;
#endif
}
Will this work ?
< / Edit 1>
That will give you a linker error of func2 not found (func2 won't be defined if you use that).
I think you might be looking for static.
static int fake(int x) { return x * 2; }
int doSomething(int x) { int tmp = fake(x); doOtherThings(); }
The fake would not exist outside of the compilation unit (file basically).
As for allowing a function to only be called from another function, that doesn't make much sense. Just inline the code if that's your end goal.
There is no real way to do it. The best that can be done in standard C is to make func2 static and define it close to the bottom of the source file:
static int func2 ()
{
return 1;
}
int func1 ()
{
func2();
}
(end of file)
Maybe you can use static keyword .
But the function with static is accessible for all the code in the same file. Other files cannot access it.

Return with Macro C programming

This code is always returning -1 even when the fopen() function has executed successfully. Is there something I am ignoring.
void nullCheck(FILE* checkVar) {
if(checkVar==NULL) {
#define _NULL_ERROR
}
}
int readFile(char* _name, char* storeArray) {
FILE* fp;
fp=fopen(_name,READ_ONLY_MODE);
nullCheck(fp);
#ifndef _NULL_ERROR
char c=0;
while((c=getc(fp))!=EOF) {
*(storeArray+i)=c;
i+=1;
}
#endif
#ifdef _NULL_ERROR
#undef _NULL_ERROR
return -1;
#endif
return 1;
}
Thanks!
Oy va voy! Macros are defined and undefined when your code is compiled, not when it runs! They are not affected by control flow statements like "if" and "then" -- they are all processed before compilation of those statements even begins!
You need to re-read the documentation on the C Preprocessor. The #define _NULL_ERROR doesn't get executed when nullCheck is called, it gets interpeted when the preprocessor processes the file before it is compiled. So you are always setting _NULL_ERROR and so you will always return -1.
#define is a preprocessor command, which means it's not calculated / processed in the function nullCheck() but before the compiling of the code. so _NULL_ERROR is always defined and therefore the condition
#ifdef _NULL_ERROR
#undef _NULL_ERROR
return -1;
#endif
will always cause the pre-compiler to add the return -1; to your code.
This is what your code looks like to the compiler, after the preprocessor runs:
void nullCheck(FILE* checkVar) {
if(checkVar==NULL) {
}
}
int readFile(char* _name, char* storeArray) {
FILE* fp;
fp=fopen(_name,READ_ONLY_MODE);
nullCheck(fp);
return -1;
return 1;
}
As has been stated above, the preprocessor deals with macros before the compiler runs.
#define, #ifdef, and friends don't work like you think they do. They're preprocessor directives that affect your code even before the compiler sees it. Get your compiler to show you the preprocessed source before it compiles (-E or -save_temps in gcc and clang) and you'll immediately see what's going on.

Resources