Can I have a function that gets defined differently due to value of some global variable -for example called "s"?
It should accept two integers if s equals 0, and one character otherwise.
I've tried using C preprocessor, but it seems that global variables cannot be accessed while preprocessing is being done.
# include <stdio.h>
int s = 1;
# if (s == 0)
void f(int x, int y);
# else
void f(char x);
#endif
int main(){
if (s == 0) f(0, 1);
else f('z');
return 0;
}
Surprisingly, in the above code f will be defined to accept two arguments, which logically is not expected.
I also do not want to change the main function.
You can do it in this way
# include <stdio.h>
#define S
# ifdef S
void f(int x, int y);
# else
void f(char x);
#endif
int main(){
# ifdef S
f(0, 1);
# else
f('z');
#endif
return 0;
}
And if you want to run the "else" version you just put the definition of S in a comment //#define S
Related
I am trying to make a function, which will execute a function with the provided sub arguments in C. Like:
int function(void (*func)(), ...) // add as many arguments you want for 'func()'
{
va_list ptr;
...
func(sub_arguments) // the '...'
}
void *abc(int a) { ... }
void *one(int b, int c) { ... }
int main()
{
function(abc, 73);
function(one, 9, 84);
}
Now, is there a way to somehow make a variable list and add it as the arguments and execute it? If so, how?
I know I phrased the question in a very difficult way, but I just don't get how to do this.
You can either extract each argument in function() and make the relevant call:
#include <stdio.h>
#include <stdarg.h>
void abc(int a) {
printf("abc(%d)\n", a);
}
void one(int b, int c) {
printf("one(%d,%d)\n", b, c);
}
int function(void (*func)(), ...) {
va_list ap;
va_start(ap, func);
if(func == abc) {
int a = va_arg(ap, int);
func(a);
} else if(func == one) {
int b = va_arg(ap, int);
int c = va_arg(ap, int);
func(b, c);
}
va_end(ap);
return 0;
}
int main() {
function(abc, 73);
function(one, 9, 84);
}
Or change your sub-functions to take a va_list, then pass it from function to the sub-function. That is probably the approach I would would take. If want to call your sub-functions directly that write a wrapper for each that accepts a ... argument (like printf() and vpritnf() pair). Note that this requires the sub-functions to have a fixed argument like function() has func.
One option could be to not use a variadic function at all but to use a C11 _Generic selection to call an implementation of function exactly matching the arguments it's supposed to relay on to func.
With this solution you'll get compile time checks that you've supplied compatible arguments instead of getting undefined behavior during runtime if you've made mistakes when supplying the arguments.
#include <stdio.h>
int function_impl_1(void(*func)(int), int a) {
func(a);
return 0;
}
int function_impl_2(void(*func)(int, int), int a, int b) {
func(a, b);
return 0;
}
#define function(X, ...) _Generic((X), \
void(*)(int): function_impl_1, \
void(*)(int, int): function_impl_2 \
)(X, __VA_ARGS__)
void abc(int a) {
printf("abc(%d)\n", a);
}
void one(int b, int c) {
printf("one(%d,%d)\n", b, c);
}
void two(int b, int c) {
printf("two(%d,%d)\n", b, c);
}
int main(void) {
function(abc, 73);
function(one, 9, 84);
function(two, 123, 456);
}
Demo
Variadic macros with zero variadic arguments are problematic. There's a GNU extension, __VA_OPT__ (from C++20), that can be used for that:
#define function(X, ...) _Generic((X), \
void(*)(void): function_impl_0, \
void(*)(int): function_impl_1, \
void(*)(int, int): function_impl_2 \
)((X) __VA_OPT__(,) __VA_ARGS__)
void zero(void) {
puts("zero()");
}
// ...
function(zero);
Demo
#include <stdio.h>
#define N 100
void f(void);
int main(void)
{
f();
#ifdef N
#undef N
#endif
return 0;
}
void f(void){
#if defined(N)
printf("N is %d\n",N);
#else
printf("N is undefined\n");
#endif // defined
}
Why does this output print N is undefined shouldn't it print N is 100 because of the function call on f before it reaches the undef that removes the value 100?
Preprocessor directives and macros are processed at a very early stage of compilation, they have no existence at runtime.
Running your code just through the preprocessor (cpp -P -- warning: remove the #include first) shows the actual C code that is being compiled.
void f(void);
int main(void)
{
f();
return 0;
}
void f(void){
printf("N is undefined\n");
}
As to why this expansion is chosen rather than the alternate message, consider these lines in your source.
#ifdef N
#undef N
#endif
Regardless of whether it's defined or not initially, it will not be defined after these lines are (pre-)processed.
I wrote a simple program to change addition to multiplication
#include<stdio.h>
#define ADD(X,Y) X+Y
void fun()
{
#ifndef ADD(X,Y)
printf("entered #ifndef");
#define ADD(X,Y) X*Y;
#endif
int y=ADD(3,2);
printf("%d",y);
}
int main()
{
#undef ADD(X,Y)
fun();
return 0;
}
The output I expect is 3*2 but the code still outputs 3+2 i.e. 5 .
The code doesn't output : "entered #ifndef", that means #undef is not working?
What is wrong here?
Edit :
Thanks to #deviantfan
Here is the correct code:
#include<stdio.h>
#define ADD(X,Y) X+Y
void fun();
int main()
{
#undef ADD(X,Y)
fun();
return 0;
}
void fun()
{
#ifndef ADD(X,Y)
printf("entered #ifndef");
#define ADD(X,Y) X*Y;
#endif
int y=ADD(3,2);
printf("%d",y);
}
The preprocessor (which processes eg #define) doesn´t know about
functions or things like that. It processes the file strictly from top to bottom,
independent how the actual code execution would jump around at runtime.
As soon as it hits your #undef, the #ifndef is long forgotten and won´t be evaluated again.
The actual solution to this problem is to use function pointers.
Here is a direct translation from your current code to function pointers.
Note the similarities and differences.
#include <stdio.h>
int actual_add(int X, int Y) {
return X+Y;
}
int actual_multiply(int X, int Y) {
return X*Y;
}
int (*ADD)(int,int) = actual_add;
void fun()
{
if (!ADD)
{
printf("entered #ifndef");
ADD = actual_multiply;
}
int y=ADD(3,2);
printf("%d",y);
}
int main()
{
ADD = NULL;
fun();
return 0;
}
The #ifdef, #ifndef and #undef preprocessor directives expect an identifier, not an expression.
#ifndef ADD(X,Y) is meaningless.
It should read: #ifdef ADD.
The same goes for #undef ADD
I have a beginner question in C. I'm having trouble in reading a file with values that initialize global variables to be shared in different C files. My true project has many variables to be used and changed across multiple files. My file that reads the parameters is:
#include <stdio.h>
#include <stdlib.h>
#include "parameters.h"
#include "prototypes.h"
#define MAX_LENGTH 100
int ReadParameters(void)
{
char line[MAX_LENGTH];
FILE *fp = fopen("parameters.in", "r");
if (! fp)
return EXIT_FAILURE;
int numread = 0;
while (fgets(line, MAX_LENGTH, fp)) {
numread += sscanf(line, "x = %d", &x);
numread += sscanf(line, "y = %d", &y);
numread += sscanf(line, "z = %d", &z);
}
fclose(fp);
return numread;
}
I defined the variables x, y, and z as external in a header file:
#ifndef PARAMETERS_H
#define PARAMETERS_H
extern int x;
extern int y;
extern int z;
#endif
The prototype of ReadParameters.c is in the header prototype.h and the values in x, y, and z are used in main.c:
#include <stdio.h>
#include <stdlib.h>
#include "parameters.h"
#include "prototypes.h"
int main()
{
ReadParameters();
printf("The value of x: %d\n", x);
printf("The value of y: %d\n", y);
printf("The value of z: %d\n", z);
x += 15;
y -= 5;
z -= 20;
printf("Now the value of x: %d\n", x);
printf("Now the value of y: %d\n", y);
printf("Now the value of z: %d\n", z);
return EXIT_SUCCESS;
}
When I compile I get the error of undefined reference to x, y, and z which I believe its because I only declared the variables not defined them. If I remove extern from the header file I get no errors and it runs but I read its not good practice to define variables in header files. If I make a another .C file and defined the variables there:
#include "parameters.h"
int x, y, z;
it works but is this ok to do? I'm new to programming and any suggestions would be appreciated. Thanks
extern means that the variables are available in some other compilation unit (ie. .c file). Typically you have one .h file for each .c file that "exposes" anything to other units.
So for something like this, I would probably have:
parameters.c
int x, y, z;
parameters.h
#ifndef PARAMETERS_H
#define PARAMETERS_H
extern int x;
extern int y;
extern int z;
#endif
main.c
#include "parameters.h"
int foo() {
x = 4; // setting x from parameters.c
}
extern tells the compiler that the definition of the variables lies else where( special case would be where variables are defined in the same compilation unit ). But linker should find these definitions. So, declare them extern in a header file(s) and include the header file in source files intended to use them. But don't forget to define them in exactly one source file. What you are doing seems ok to me.
it works but is this ok to do?
It is indeed regarded as bad practice, since it leads to "tight coupling" and spaghetti code.
The preferred way is this:
//parameters.h
void set_x (int x);
//parameters.c
#include "parameters.h"
static int private_x; // static means: only visible/accessible from parameters.c
void set_x (int x)
{
private_x = x;
}
// main.c
#include "parameters.h"
set_x (something);
What does this mean?
void message(int x, int y, ...)
I can't understand what ... is.
Can anybody explain?
... denotes a variable list of arguments that can be accessed through va_arg, va_end and va_start.
Unspecified/variable number of parameters. To handle such function you have to use the va_list type and va_start, va_arg, and va_end functions:
An example taken from here:
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
int maxof(int, ...) ;
void f(void);
main(){
f();
exit(EXIT SUCCESS);
}
int maxof(int n args, ...){
register int i;
int max, a;
va_list ap;
va_start(ap, n args);
max = va_arg(ap, int);
for(i = 2; i <= n_args; i++) {
if((a = va_arg(ap, int)) > max)
max = a;
}
va_end(ap);
return max;
}
void f(void) {
int i = 5;
int j[256];
j[42] = 24;
printf("%d\n",maxof(3, i, j[42], 0));
}
You can find more details here
You have defined a function message somewhere that takes at least two arguments of type int and then some optional arguments indicated by the "...". (printf is another function taking optional arguments).
The optional arguments can be accessed using the va_* functions.
... represents final argument passed as an array or as a sequence of arguments.
It's the variable argument formal parameter. From the syntactical prospective it allows you pass a variable number of parameters (at least two, which are x and y, but even more).