I'm playing around with macros and I managed to do a stack structure that can work with any type, but the thing is I have a problem with the POP
function, it has to pop the value out of the stack and return it, for that I'm using a statement expression. The thing is when the stack is empty, I have to return a default value, but I don't know the type of the variable so I can't just return NULL
or INT_MIN
because it can be a pointer, an integer, an array or a struct. What I want to do is initialize that variable to a default value like for static variables (they auto initialize to either 0
or {}
). Here is the code I wrote for the context. (The code works but when POP
fails it returns an undefined uninitialized value, so it can't compile with -Wall -Wextra -Werror
)
#ifndef STACK_H
# define STACK_H
# include <sys/types.h>
# include <stdint.h>
# include <stdbool.h>
# include <stdlib.h>
# define STACK(type, cap) struct {\
size_t capacity;\
size_t size;\
type data[cap];\
}\
# define STACK_INIT(stack) \
(stack) = (typeof(stack)) {\
.capacity = sizeof((stack).data) / sizeof(*(stack).data),\
.size = 0,\
.data = {}\
}
# define STACK_PUSH(stack, value) ({\
bool ret = true;\
\
if ((stack).size == (stack).capacity) ret = false;\
(stack).data[(stack).capacity - ++(stack).size] = value;\
ret;\
})
# define STACK_POP(stack) ({\
typeof(*(stack).data) ret;\ // Here ret is declared
\
if ((stack).size) ret = (stack).data[(stack).capacity - (stack).size--];\
\ // else ret is uninitialized, is it possible to give it a default value without knowing its type?
ret;\
})
# define STACK_SIZE(stack) stack.size
# define STACK_EMPTY(stack) !stack.size
#endif
Example of simple usage:
#include <stdio.h>
#include "stack.h"
int main(int argc, char **argv) {
if (argc < 2) {
dprintf(2, "Usage: %s <at least one argument>\n\n", argv[0]);
return (-1);
}
STACK(char *, 10) stk;
STACK_INIT(stk);
for (int i = 1; i < argc; ++i)
if (!STACK_PUSH(stk, argv[i])) {
dprintf(2, "Failed to push\n\n");
return (-1);
}
while (!STACK_EMPTY(stk))
printf("%s\n", STACK_POP(stk));
return (0);
}
I don't think this is possible in C.
But one solution is to assume that a default value is zero-byte initialized, and write code like:
typeof(*(stack).data) ret; \
memset(&ret, 0, sizeof(ret)); \