How could I correct this macro? - c

I wrote this for my homework:
#define SUMARRAY(array, size) ({ \
int sum = 0; \
for (int i = 0; i < size; i++) \
{ \
sum += array[i]; \
} \
sum; \
})
The warning is:
ISO C forbids braced-groups within expression
Edit:
Compiler:
gcc (MinGW.org GCC-6.3.0-1) 6.3.0
ISO C11
The assignment is:
Write a program that defines and uses macro SUMARRAY to sum the values in a numeric array. The macro should receive the array and the number of elements in the array as arguments.

There is no need to use a macro for this.
You use a gcc extension to create an expression from a statement, which your compiler refuses under strict ISO C conformance option (-std=c90 or similar), there is no simple solution to write this macro is a conformant way.
Note these extra problems with this macro:
the macro arguments are not parenthesized in the expansion, so you may experience precedence problems if you pass expressions.
the macro defines new variables i and sum... This will pose a problem if you already have variables with these names where you instantiate the macro, especially if you pass sum or i as a macro argument.
the macro assumes array has integer contents
Here is a safer way to write this macro:
#define SUMARRAY(array, size) ({ \
int sum__ = 0; \
size_t size__ = (size); \
typeof(*(array)) *array__ = (array); \
for (size_t i__ = 0; i__ < size__; i__++) \
sum__ += array__[i__]; \
sum__; \
})
I would recommend you write a function instead:
static inline int sumarray(const int *array, int size) {
int sum = 0;
for (int i = 0; i < size; i++)
sum += array[i];
return sum;
}
If you really need to use a macro, write it as a simple wrapper:
#define SUMARRAY(array, size) sumarray(array, size)

Related

Can macro in c generate serialized statement? [duplicate]

I want to generate an array initializer with arbitrary logic that unfortunately requires some looping.
#define RANDOM_ARRAY(n) \
...
double array[] = RANDOM_ARRAY(10);
Suppose the code above generates an initializer for a 10-element array. Is it possible to define such a macro (with a loop) in C99 ?
NB: it doesn't have to be a macro if a function call could suffice (but it has to be possible to call it among global initializers, not in a second function);
Unfortunately, it is not possible to create a recursive (or loop) macrofunction in C. Nevertheless, if you have a reasonable maximum length for your initializer, you can use this type of construct :
#define INITIALIZER(N) { INITIALIZER_ ## N }
#define INITIALIZER_1 1
#define INITIALIZER_2 INITIALIZER_1, 2
#define INITIALIZER_3 INITIALIZER_2, 3
int
main(void)
{
int tab[3] = INITIALIZER(3);
return 0;
}
The C preprocessor doesn't support loops, so what you want is not (easily) possible.
I added the '(easily)' because there are ways to get loop-like behavior using something like boost's ITERATE. This uses recursive file inclusion to emulate a loop. But I'm not sure if you want to go that far.
Since you're working in C99, you can of course create a macro that does the initialization, but you won't be able to make it look like an initializer:
#define INCREMENTING_ARRAY(t,a,n) t a[n]; do {\
for(size_t i = 0; i < n; ++i)\
a[i] = i;\
} while(0);
This creates an array whose elements are initialized to be incrementing, as an example.
Usage:
int main(void)
{
INCREMENTING_ARRAY(int, dozen, 12);
int i;
for(i = 0; i < sizeof dozen / sizeof *dozen; ++i)
printf("array at %d = %d\n", i, dozen[i]);
return 0;
}
This works since in C99 you can freely mix declarations and code, so the int i; after the macro usage is fine. In C89, it wouldn't have worked.

Use of pasting operator `##` with types in C

Is it possible to define a macro for the C preprocessor which takes an array as argument and expands to <type of array elements>_string? For example if x in an array of integers the macro invoked with argument x should expand to int_string.
I tried with
#define TypePaste(array) typeof(array[0])##_string
but it expands to )_string.
Even using multiple levels of indirection for the ## operand the macro doesn't expand correctly.
That's not possible. At the translation phase (the preprocessing phase) where macros are expanded and tokens are concatenated, the compiler (at this point, the preprocessor) does not yet have the notion of a type and thus cannot possibly generate types.
It is not all that clear what problem you are trying to solve, but given your comment:
the macro should expand to the name of an existing function. I'd like to define a function <type>_string for every existing type and then use the macro to select the right function according to the type of the array given.
Then you could use the C11 _Generic keyword:
#include <stdio.h>
void int_string (size_t size, int array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
void float_string (size_t size, float array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
#define TypePaste(array) \
_Generic( array, \
int: int_string, \
float: float_string ) \
(sizeof(array)/sizeof(*array), array) // function parameters
int main()
{
int i_arr[5];
float f_arr[3];
TypePaste(i_arr);
TypePaste(f_arr);
}
Output:
I am int_string, do stuff here.
I am float_string, do stuff here.
Note: this assumes that the passed parameter is a local/file scope allocated array. If passing a pointer, there's no type safety and the program will fail.
C11's _Generic type selection is the "proper" way to do what you want. There are other, platform dependent solutions, tough.
If you are using gcc – you don't say so eplicitly, but you use gcc's extension typeof already – you can use gcc's statement expresions and nested functions to create a comparison function for qsort on the spot:
double a[5] = {8.4, 8.1, 9.3, 12.2, 5.2};
qsort(a, 5, sizeof(*a), ({
int cmp(const void *p, const void *q) {
const typeof(a[0]) *pp = p;
const typeof(a[0]) *qq = q;
return (*pp < *qq) ? -1 : (*pp > *qq);
}
cmp;
}));
This creates a function and returns its address. (The last statement of a compound expression is its value. The scope of the local variables is the statement expression, but a nested function is not created on the stack so its safe to return a pointer to that function.)
For primitive types, where you want to sort according to the comparison operators < and >, you can turn that into a macro:
#define COMPARE(ARRAY)({ \
int cmp(const void *p, const void *q) { \
const typeof(ARRAY[0]) *pp = p; \
const typeof(ARRAY[0]) *qq = q; \
return (*pp < *qq) ? -1 : (*pp > *qq); \
} \
cmp; \
})
qsort(a, 5, sizeof(*a), COMPARE(a));
or even:
#define SORT(ARRAY, N) \
qsort(ARRAY, N, sizeof(*ARRAY), COMPARE(ARRAY))
SORT(a, 5);
That's not Standard C, so if you need compatibility between platforms, this is out of the question.

C Macro with varargs

I am trying to write a macro which returns the smallest value of several integers. When I compile the following code, it throws an error "expected expression". I don't know what's wrong there. Could anyone point out the issues with this code?
#define SMALLEST (nums, (ret_val), ...) \
do { \
int i, val; \
va_list vl; \
va_start(vl,nums); \
(*ret_val) = va_arg(vl, int); \
for (i = 1; i < nums; i++) \
{ \
val=va_arg(vl, int); \
if ((*ret_val) > val) \
(*ret_val) = val; \
} \
va_end(vl); \
} while(0)
int main ()
{
int nums = 3;
int ret_val = 0;
SMALLEST(nums, &ret_val, 1, 2, 3);
return 0;
}
I am just curious about how to do it with Macro.
I am just curious about how to do it with Macro.
You can't. va_list is a way for a variadic function to access its arguments. What you have written is a variadic macro. They are not the same (in particular the variadic macro is still only a syntactic convenience that does not let you process individual arguments). The only way to do what you want is to call a variadic function of your own design inside the variadic macro (and then you might as well eliminate the macro).
However, if you really insist on using a variadic macro, it turns out that you are lucky that the same separator , is used in macro arguments and in array initializers, so you can try something like:
#define F(X, ...) \
do { \
int t[] = { __VA_ARGS__ }; \
for (int i = 0; i < sizeof t / sizeof t[0]; i++) \
… \
} while (0)
I don't think you can. From the gcc manual (https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html) the best you can do in a standard way is write __VA_ARGS__, which will expand the arguments in place (for example to pass to a function).
It then goes on to define other non-standard extensions, which you might be able to use, but wouldn't be standard.
Why not do it with a function?
The way you deal with argument lists in variadic macros is not the same as the way you deal with them in variadic functions. Instead of using va_list and its related macros, you use __VA_ARGS__.
That is pretty much the extent of it: you cannot write a macro that processes variadic list from the beginning to the end; you are limited to passing the arguments through to a variadic function, which performs the actual processing.
Note: Your implementation is incorrect, too: you should be using va_start(vl,ret_val) instead of va_start(vl,nums), because you are supposed to pass the last argument before ... to va_start.
If I were to rewrite this as a function, though, I would drop the ret_val pointer, and make a function that returns a value the regular way.
It makes no sense to do that with macro. That's what functions are for.
You get an error because the SMALLEST symbol in your main function gets replaced by the whole body of the function you've defined. AFAIK you can't define a function inside another function in C.
Is there any particular reason why you want to use a macro here? You seem to be confusing macro syntax and standard syntax (the reason for your error).
You should use a function to achieve this - this is what a function is for. The following code should get you what you want:
int Smallest( int iNumberOfIntegers, ... )
{
va_list args = NULL;
int i = 0;
int iSmallestValue = 0;
int iCurrentValue = 0;
va_start( args, iNumberOfIntegers );
iSmallestValue = va_arg( args, int );
for(i = 0; i < iNumberOfIntegers - 1; i++)
{
iCurrentValue = va_arg( args, int );
if(iSmallestValue > iCurrentValue)
{
iSmallestValue = iCurrentValue;
}
}
return iSmallestValue;
}
Of note, you you need to pass the size of the variadic argument if you are going to loop over it in this manner. This is not necessary in format strings because the compiler can infer the number from the format string specifiers.
We subtract 1 from the loop to account for a 0 offset.
Edit: And, as others have said, you can't use a variadic macro in the way you were trying.

Using preprocessor directives to define generic functions in C

I just came to C from C# and was looking for a way to define generic functions like those in C#. I came across this post but when I tried to compile it I get a bunch of errors ("`n' undeclared here (not in a function)", " syntax error before "array" ", etc.)
Here's my code:
#include<conio.h>
#include<stdlib.h>
#define MAKE_PRINTEACH(TYPE)\
void printeach_##TYPE (TYPE[n] array, int n, void(*f)(TYPE)){\
int i;\
for(i = 0; i < n; i++) {\
f(array[i]);\
}\
}
MAKE_PRINTEACH(int)
MAKE_PRINTEACH(float)
void printInt(int x)
{
printf("got %d\n",x);
}
void printFloat(float x)
{
printf("got %f\n",x);
}
int main()
{
int[5] ia = {34,61,3,6,76};
float[6] fa = {2.4,0.5,55.2,22.0,6.76,3.14159265};
printeach_int(ia, 5, printInt);
printeach_float(fa,6,printFloat);
getch();
}
What am I doing wrong here?
I am using DevC++ if that makes a difference.
A correct version would look like this
#define MAKE_PRINTEACH(TYPE) \
void printeach_##TYPE (size_t n, TYPE array[n], void(*f)(TYPE)){ \
for(size_t i = 0; i < n; i++) { \
f(array[i]); \
} \
}
to summarize what went wrong with your version:
n must be declared before it is used
the array bounds come after the identifier
the semantically correct type for array sizes and things like that is size_t
C since C99 also has local variables for for loops.
You might try this variation:
#define MAKE_PRINTEACH(TYPE)\
void printeach_##TYPE (TYPE * array, int n, void(*f)(TYPE)){\
int i;\
for(i = 0; i < n; i++) {\
f(array[i]);\
}\
}
The TYPE[n] array implies the compiler supports VLA (Variable Length Array) and I do not know whether your compiler does.
For gcc adding the command line option -std=c99 would make the original code compile.
Update:
Corrections applied as by Jens's comment.
The solution I propose is to simply pass a pointer to a variable of the type which the array (as proposed in the OP) would have contained. Doing so, is the way arrays are passed to a function. They are passed by reference.
Also Jens mentions several other warnings/errors. As there are:
1 conio.h is not a standard C include, stdio.h whould be appropriate here
2 Arrays are declared by adding the array's size to the variable name, not to the type. It has to be: int ia[5]not int[5] ia
3 main() returns int, the OP does not return anything.
4 The prototype for getch() is missing. One might like to include curses.h

How do I #define an array in C?

Is the following syntax to define an array valid syntax in C?
#define array[] { \
for (j=0; j<N_frequencysteps;j++) \
{ \
array[j] = (function); \
} \
}
If not, how do I define an array in C?
It depends on how you define 'valid syntax'.
The C pre-processor will accept it as an object-like macro.
The C compiler will not accept the output as legitimate C.
Consider an invocation:
array[23];
The C compiler sees:
[] { for (j=0; j<N_frequencysteps;j++) { array[j] = (function); } } [23];
That is gibberish (even with the 'enter code here' removed).
How can you define an array in C?
enum { ARRAYSIZE = 23 };
int array[ARRAYSIZE];
int j;
for (j = 0; j < ARRAYSIZE; j++)
array[j] = 0;
You could also use an initializer, but you might get compiler warnings unless you are thorough:
int array[ARRAYSIZE] = { 0 };
One more possibility: if you want to define an array and initialize it with calls to a specific function, then you could, I suppose, try:
#define ARRAY(type, name, size, initializer) type name[size]; \
for (int j = 0; j < size; j++) name[j] = initializer
This could be used as:
ARRAY(int, array, 23, j % 9);
(Note that this initializer depends on an implementation detail of the macro - not a good idea. But I don't think I'd ever use such a macro, anyway.) It depends on you being in C99 mode if you have more than one of these in a particular block of code (since it would then mix code with declarations) - and also because the declaration in the for loop is only supported in C++ and C99, not in C90.
This looks really wrong. Why not define array in a normal way?
int array[SIZE];
for (j=0; j<N_frequencysteps;j++)
{
array[j] = (function);
}

Resources