Lazuli
Loading...
Searching...
No Matches
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
32typedef __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 */
101typedef 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