Lazuli
stdarg.h
Go to the documentation of this file.
1 /*
2  * SPDX-License-Identifier: GPL-3.0-only
3  * This file is part of Lazuli.
4  */
5 
15 #ifndef STDARG_H
16 #define STDARG_H
17 
18 #ifdef __GNUC__
19 
20 /*
21  * This implementation relies on GCC builtins. This is contradictory with the
22  * goal of implementing all of this project in pure C. However, the other
23  * implementation shown in this file, which is pure C, suffers from severe
24  * limitations. So for now we prefer to keep using this implementation as it
25  * imposes less constraints to the final user.
26  */
27 
32 typedef __builtin_va_list va_list;
33 
40 #define va_start(ap, last) __builtin_va_start(ap, last)
41 
51 #define va_arg(ap, type) __builtin_va_arg(ap, type)
52 
58 #define va_end(ap) __builtin_va_end(ap)
59 
68 #define va_copy(dest, src) __builtin_va_copy(dest, src)
69 
70 #if 0
71 
72 /*
73  * Here we introduce another possible implementation: thanks to the AVR GCC
74  * calling convention, we can implement access to parameters of variadic
75  * functions in pure C.
76  * However, be aware that this implementation has the following flaws:
77  * - It doesn't work with structures passed by value (read below).
78  * - It doesn't work when GCC chooses to inline a function.
79  *
80  * So if you really want to use this implementation, make sure to:
81  * - Never pass a structure by value to a function.
82  * - Use the appropriate compiler attribute to tell the compiler to NEVER inline
83  * the variadic function.
84  *
85  * The conclusion for now is that any of the two implementation in this file
86  * require the use of compiler specifics/builtins (unfortunately).
87  * We choose to show this implementation here as a starting point for further
88  * investigation, if needed.
89  *
90  * For the AVR caling convention on GCC, see:
91  * https://gcc.gnu.org/wiki/avr-gcc
92  */
93 
94 #include <stdint.h>
95 
100 /* We choose uint8_t here, but it works with any type of size == 1 */
101 typedef uint8_t* va_list;
102 
109 #define va_start(ap, last) \
110  (ap) = (va_list)((&(last)) + 1)
111 
121 /*
122  * Again, this is very specific to the AVR GCC calling convention.
123  *
124  * It works because in C the assignment operator "=" have higher precedence than
125  * the comma "," operator. i.e. In this definition the part before the comma is
126  * part of an assignment when the macro is called, so the assignment will be
127  * evaluated first, then everything that is after the comma is executed.
128  *
129  * One note: it seems that passing structure by value is not supported because
130  * AVR GCC doesn't follow the usual ABI rules for pushing these types on the
131  * stack. For example, trying with a structure of size 3, the compiler will push
132  * every byte of it without padding to round up its size to the next even value.
133  * Even structures of size 1 seem to have the same behaviour.
134  */
135 #define va_arg(ap, type) \
136  /* First, we dereference to get the value */ \
137  (*(type*)ap), \
138  /* Then we need to point after the object we just get, */ \
139  /* So if its size is an odd number of bytes */ \
140  ((sizeof(type) & 1) ? \
141  /* We round it up to the next even size before pointing */ \
142  /* to the next value */ \
143  (ap += sizeof(type) + 1) : \
144  /* Else we point directly after the value */ \
145  (ap += sizeof(type)))
146 
152 #define va_end(ap) \
153  do {} while (0)
154 
163 #define va_copy(dest, src) \
164  dest = src
165 
166 #endif /* 0 */
167 
168 #else /* __GNUC__ */
169 #error "stdarg.h is not implemented for this compiler."
170 #endif
171 
172 #endif /* STDARG_H */
unsigned char uint8_t
Represents a unsigned integer type with width of exactly 8 bits.
Definition: stdint.h:89