Custom array macro not working as intended - arrays

I wanted to make a custom array in C like std::array in C++. However the following code doesn't work.
array.h:
#ifndef CUSTOM_ARRAY
#define CUSTOM_ARRAY
#define array(T, name, n_elements) do { \
T name [(n_elements)]; \
} while(0)
#endif
main.c:
#include "array.h"
#include <stdio.h>
int main()
{
array(int, array_name, 5);
size_t size_of_array = sizeof(array_name) / sizeof(array_name[0]);
for (int i = 0; i < size_of_array; i++) {
array_name[i] = i;
printf("%d\n", array_name[i]);
}
return 0;
}
It displays the following errors message:
main.c: In function 'main': main.c:10:35: error: 'array_name' undeclared (first use in this function) 10 | size_t size_of_array = sizeof(array_name) / sizeof(array_name[0]); | ^~~~~~~~~~ main.c:10:35: note: each undeclared identifier is reported only once for each function it appears in
But in main.c, doesn't the array in the macro expand into:
int array_name[5];

You are limiting the scope of the array to that one statement.
Replace
#define array(T, name, n_elements) do { \
T name [(n_elements)]; \
} while(0)
with
#define array( T, name, n_elements ) T name[ n_elements ]

Related

Define a function pointer to be32toh() function

I'm newly learned about function pointers here but I couldn't define a function pointer to be32toh() or other functions of endian.h header.
First of all, I can do what is told in the given thread:
#include <endian.h>
int addInt(int n, int m) {
return n+m;
}
int main(){
int (*functionPtr)(int,int);
functionPtr = addInt;
return 0;
}
But when I try to do the same for a function like be32toh(), I'll get a compilation error:
#include <stdint.h>
#include <endian.h>
int addInt(int n, int m) {
return n+m;
}
int main(){
int (*functionPtr)(int,int);
functionPtr = addInt;
uint32_t (*newptr)(uint32_t);
newptr = &be32toh;
return 0;
}
Compile as:
$ gcc test.c
Result is as below:
test.c: In function ‘main’:
test.c:15:15: error: ‘be32toh’ undeclared (first use in this function)
15 | newptr = &be32toh;
| ^~~~~~~
test.c:15:15: note: each undeclared identifier is reported only once for each function it appears in
What's the problem and how to fix it?
What's the problem
be32toh is a macro.
how to fix it?
Just write the function yourself.
uint32_t be32toh_func(uint32_t a) {
return be32toh(a);
}
....
newptr = &be32toh_func;

Can anyone recommend a way to write a function that counts the number of fields in a struct? i.e. - pseudocode- 'for field in struct'

I want a C function that I can pass a structure to and it will return the number of fields/members within the structure.
At the moment I've found the easiest way is to just make a table and add to the table anytime I add a struct to any of the programs.
I guess I'm experiencing an XY problem (per the suggestions) So anyway, the reason why I would have use for this type function is because I'm wanting to send structures over a socket and to avoid the whole serialization process the way in which i'm trying to do this is by adding delimiters to the structure's field members. Like this:
0x001 --> hdrdata --> 0x003 --> hdrdata --> 0x017 --> 0x002 --> bodydata --> 0x003 --> bodydata --> 0x003 --> bodydata --> 0x004
As you can see there may be 1 bodydata or there may be 10 bodydata etc. The only other thing I can quickly think to do is add a member to my structs that would inform my header how many 'bodydata' transmissions will be coming through so the client knows how many 0x003's to expect.
Or (and i'm not asking for an answer to this but feel free if you are so inclined) can anyone recommend a better protocol design for sending structures over socket in unix? Most of this project is for my own learning so i'm not interested in using an already complete library/package solution otherwise i'd just be writing this in another language in the first place.
This is very very ugly, but the only thing I can think of is an X-Macro:
#include <stdio.h>
#define MEMBERS \
X(char a) \
X(float b) \
X(double c)
struct T {
#define X(x) x;
MEMBERS
#undef X
};
int main(void)
{
size_t n = 0
#define X(x) +1
MEMBERS
#undef X
;
printf("%zu members\n", n);
return 0;
}
This expands to:
#include <stdio.h>
struct T {
char a;
float b;
double c;
};
int main(void)
{
size_t n = 0+1+1+1;
printf("%zu members\n", n);
return 0;
}
As pointed out by #HAL9000 in comments, you can generate both (the struct and the counter) at the same time in this way:
#include <stdio.h>
#define GENERATE_STRUCT(s) s;
#define GENERATE_SCOUNT(s) +1
#define set_struct(name) \
struct name { \
name##_members(GENERATE_STRUCT) \
}; \
\
size_t name##_count(void) \
{ \
return 0 \
name##_members(GENERATE_SCOUNT) \
; \
}
#define foo_members(X) \
X(char a) \
X(float b) \
X(double c)
set_struct(foo)
int main(void)
{
printf("%zu members\n", foo_count());
return 0;
}
In this case is expanded to:
#include <stdio.h>
struct foo {
char a;
float b;
double c;
};
size_t foo_count(void)
{
return 0+1+1+1;
}
int main(void)
{
printf("%zu members\n", foo_count());
return 0;
}
Finally, another implementation provided by #Lundin using an enum instead of a variable:
#include <stdio.h>
#define MEMBERS \
/* type name */ \
X(char, a) \
X(float, b) \
X(double, c) \
struct T {
#define X(type, name) type name;
MEMBERS
#undef X
};
enum
{
#define X(type, name) dummy_##name,
MEMBERS
#undef X
MEMBER_COUNT
};
int main(void)
{
printf("%d members\n", MEMBER_COUNT);
return 0;
}
Expands to:
#include <stdio.h>
struct T {
char a;
float b;
double c;
};
enum {
dummy_a,
dummy_b,
dummy_c,
MEMBER_COUNT
};
int main(void)
{
printf("%d members\n", MEMBER_COUNT);
return 0;
}

Macro to replace nested for loops

I found this macro #define TIMES(x) for(int i1=0;i1<x;i1++)very pratical to shorten the code text. But I do not know how to write such a macro when I have nested loops and even I do not know if it is possible. The idea is the following. Is it possible to write this code
for(int i1=0;i1<5;i1++)
for(int i2=0;i2<3;i2++)
for (int i3=0;i3<7;i3++)
/* many nested `for` loops */
{
/* some code, for example to print an array printf("%d \n",a[i1][i2][i3]) */
}
as
TIMES(5) TIMES(3) TIMES(7) ....
{
/* some code, for example to print an array printf("%d \n",a[i1][i2][i3]) */
}
with a sort of "recursive" macro that detects all TIMES and replaces them by a forloop with i1, i2, i3, ... i'n' loop counters ?
This is very bad practice, don't do this. Other C programmers are perfectly aware of for loops, but they are completely oblivious to your private, secret macro language. In addition, function-like macros like these have poor type safety and should only be used as the last resort.
The correct solution is not to use a macro, but a function. If you wish to utilize proper generic programming, you could write it as follows:
typedef void callback_t (int data);
void traverse (size_t n, int data[n], callback_t* callback)
{
for(size_t i=0; i<n; i++)
{
callback(data[i]);
}
}
Where callback is a function pointer provided by the caller, which contains the actual functionality. Similar to the loop body in your macro.
Full example:
#include <stdio.h>
typedef void callback_t (int data);
void traverse (size_t n, int data[n], callback_t* callback)
{
for(size_t i=0; i<n; i++)
{
callback(data[i]);
}
}
void print (int i)
{
printf("%d ", i);
}
int main (void)
{
int array [5] = {1, 2, 3, 4, 5};
traverse(5, array, print);
}
EDIT:
In the above example, the data type was int. But since it is generic programming, you can do some tweaks and swap it for any other data type, such as an array or a struct. The catch then is that you must pass the parameter to the callback through a pointer, instead of passing it by value. Example:
#include <stdio.h>
/* Generally it is bad practice to hide arrays behind typedefs like this.
Here it just done for illustration of generic programming in C. */
typedef int data_t[3];
typedef void callback_t (data_t* data);
void traverse (size_t n, data_t data[n], callback_t* callback)
{
for(size_t i=0; i<n; i++)
{
callback(&data[i]);
}
}
void print_array (int(*array)[3])
{
int* ptr = *array;
printf("{%d %d %d}\n", ptr[0], ptr[1], ptr[2]);
}
int main (void)
{
int array [2][3] = { {1, 2, 3}, {4, 5, 6} };
traverse(2, array, print_array);
}
This closely follows Lundin's solution, but is refactored into something more generalized.
To generically step through elements, you can leave your arguments as void *, similar to qsort and bsearch.
typedef void cb_type (void *base, size_t sz);
void
traverse (void *base, size_t n, size_t sz, cb_type *cb) {
char *p = base;
for (size_t i = 0; i < n; ++i) {
cb(p + i*sz, sz);
}
}
The callback is passed the sizeof of the element. The callback function is supposed to be aware of the underlying type of the object, so it can properly deduce which dimension is being traversed. For example, if traversing a int[4][5][6]:
int array[4][5][6];
traverse(array, 4, sizeof(*array), print_456);
And the print function could look like this:
void
print_456 (void *base, size_t sz) {
if (sz == 5 * 6 * sizeof(int)) {
traverse(base, 5, 6*sizeof(int), print_456);
puts("");
} else if (sz == 6 * sizeof(int)) {
traverse(base, 6, sizeof(int), print_456);
puts("");
} else
printf("%d ", *(int *)base);
}
Try It Online
I finally succeed in writing this macro. I found most of the informations to do that in this very good article (http://jhnet.co.uk/articles/cpp_magic). The following posts (Can we have recursive macros?, Is there a way to use C++ preprocessor stringification on variadic macro arguments?, C++ preprocessor __VA_ARGS__ number of arguments, Variadic macro trick, ...) help me also a lot.
This answer is intended to answer question. It does not address the question of macro and good programming pratices. It is another subject.
This is the code
#define SECOND(a, b, ...) b
#define IS_PROBE(...) SECOND(__VA_ARGS__, 0)
#define PROBE() ~, 1
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define NOT(x) IS_PROBE(CAT(_NOT_, x))
#define _NOT_0 PROBE()
#define BOOL(x) NOT(NOT(x))
#define IF_ELSE(condition) _IF_ELSE(BOOL(condition))
#define _IF_ELSE(condition) CAT(_IF_, condition)
#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE
#define _IF_0(...) _IF_0_ELSE
#define _IF_1_ELSE(...)
#define _IF_0_ELSE(...) __VA_ARGS__
#define EMPTY()
#define EVAL(...) EVAL1024(__VA_ARGS__)
#define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__))
#define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__))
#define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__))
#define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__))
#define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__))
#define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__))
#define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__))
#define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) __VA_ARGS__
#define DEFER1(m) m EMPTY()
#define DEFER2(m) m EMPTY EMPTY()()
#define FIRST(a, ...) a
#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)())
#define _END_OF_ARGUMENTS_() 0
#define MAP(m, first, ...) \
m(first,__VA_ARGS__) \
IF_ELSE(HAS_ARGS(__VA_ARGS__))( \
DEFER2(_MAP)()(m, __VA_ARGS__) \
)( \
/* Do nothing, just terminate */ \
)
#define _MAP() MAP
#define PP_NARG(...) \
PP_NARG_(,##__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
z,_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
#define PP_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
#define TIMES(...) EVAL(MAP(TIME2FOR,__VA_ARGS__))
#define TIME2FOR(x,...) \
for(int CAT(i,PP_NARG(__VA_ARGS__))=0; \
CAT(i,PP_NARG(__VA_ARGS__))<x; \
CAT (i,PP_NARG(__VA_ARGS__))++)
main() {
int a[3][2][4];
TIMES(3,2,4) a[i2][i1][i0]=i2*100+i1*10+i0;
TIMES (3,2,4) printf("a[%d][%d][%d] : %d\n",i2,i1,i0,a[i2][i1][i0]);
TIMES (3,2,4) {/* whatever you want : loop indexes are ...,i2,i1,i0 */}
}
It turned out to be more difficult than I thought it would be.

error: dm_mmc_ops undeclared (first use in this function)

I'm constructing an u-boot bootloader for my embedded system (cyclone V) using Buildroot and I get the following error :
error: 'dm_mmc_ops' undeclared (first use in this function)
After several unsuccessful attempts to understand/solve the error, I've manage to isolate the problem which looks like the simple code hereafter and generates the same error :
File1.h
#ifndef FILE1
#define FILE1
struct dm_mmc_ops {
int (*send_cmd)(int data);
int (*set_ios)(char* dev);
};
struct dev {
struct dm_mmc_ops* ops;
} *dev;
#define mmc_get_ops(dev) ((dm_mmc_ops *)(dev)->ops)
#endif
File2.h
#ifndef FILE2
#define FILE2
#include "file1.h"
extern const struct dm_mmc_ops dm_dwmci_ops;
#endif
File2.c
#include <stdio.h>
#include "file1.h"
#include "file2.h"
int return_int (int data)
{
return data;
}
int return_ptr (char* data)
{
return (int) data;
}
const struct dm_mmc_ops dm_dwmci_ops = {
.send_cmd = return_int,
.set_ios = return_ptr
};
void main (void)
{
struct dev my_dev = {.ops = &dm_dwmci_ops};
dev = &my_dev;
char text[] = "abcd";
struct dm_mmc_ops *test_mmc = mmc_get_ops(dev); // Error is here !!!
printf("%d\n",test_mmc->send_cmd(50));
printf("%d\n",text);
printf("%d\n",test_mmc->set_ios(text));
return;
}
Then the error generated is :
error: 'dm_mmc_ops' undeclared (first use in this function)
What is wrong in my code and what should I do to get rid of this error ?
Your problem is here
#define mmc_get_ops(dev) ((dm_mmc_ops *)(dev)->ops)
^^^^^^^^^^
You probably want
#define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->ops)
Besides that you have a number of other problems. Set you compiler to a high warning level (e.g. gcc -Wall ...) and then fix all warnings.

test1.c:7: error: syntax error before '{' token

I am trying to create a multiline macro and i am facing this error.
#include<stdio.h>
#define call(a) \
if ((a)>0) \
printf("printing a %d:"a)
int main
{
int a =10;
call(a);
return 0;
}
int main needs to be written as int main().
Also, there should be no whitespace after the final \ of a multi-line macro. That can cause spurious compiler errors.
C function declaration requires parentheses, with or without parameters.
int f { ... } // incorrect
int f() { ... } // correct
Missing "," in prinf() function befor variable "a".
#include<stdio.h>
#define call(a)\
if ((a)>0)\
printf("printing a %d:",a)
int main()
{
int a =10;
call(a);
return 0;
}

Resources