Sujet : Re: Is it possible to generate a compile time error from an inline function?
De : tr.17687 (at) *nospam* z991.linuxsc.com (Tim Rentsch)
Groupes : comp.lang.cDate : 13. Jul 2024, 19:50:48
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <86ikx96s8n.fsf@linuxsc.com>
References : 1
User-Agent : Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Alan Mackenzie <
acm@muc.de> writes:
Hello, comp.lang.c.
>
What I want to do is check the validity of (constant) arguments to an
inline function, and output a compiler error if they are invalid.
>
In particular, I have:
>
u32 __always_inline ACM_BITFIELD (u8 a[], int offset, int length)
>
, which is to extract a bitfield of LENGTH bits, starting at bit number
OFFSET in the array of bytes A. OFFSET and LENGTH will be known at
compile time.
>
For the sake of run time efficiency, I wish to impose the restrictions
that either (i) the bitfield will be contained entirely within a byte; or
(ii) the bitfield will be a number of consecutive whole bytes (maximum 32
bits).
>
So, for example, if the code called
>
foo = ACM_BITFIELD (bar, 14, 4);
>
, I would like to output the compiler message "Invalid arguments 14, 4,
to ACM_BITFIELD", since this bitfield straddles two bytes.
>
Is there any way I can do this in C? (Before anybody asks, yes I have
looked at doing it with macros, but that seems impractical, if it's even
possible.)
First, I don't know why you think doing this with macros is
impractical. I knocked out a full macro version without too much
difficulty.
Second, if the C you're using has _Static_assert available, the test
can be done using that. (Richard Damon explains how to get a
similar effect to _Static_assert for C versions before C99.)
Here is an illustrating implementation in C11. I changed the types
of the arguments offset and length to be unsigned but otherwise it
is just as you outlined. Oh, the error message has an extra pair of
parentheses to avoid problems with macro processing.
typedef unsigned char u8;
typedef unsigned u32;
static inline u32 (ACM_BITFIELD)( u8 a[], unsigned, unsigned );
#define ACM_BITFIELD( bytes, offset, length ) ( \
(void) ACM_BITFIELD_SANITY_CHECK( offset, length ), \
(ACM_BITFIELD)( (bytes), (offset), (length) ) \
)
#define ACM_BITFIELD_SANITY_CHECK( o, n ) ( \
(struct { \
int x; \
_Static_assert( \
ACM_BITFIELD_TEST_( (o), (n) ), \
STRINGIZE( Invalid arguments (o,n) to ACM_BITFIELD ) \
); \
}) {1} \
)
#define ACM_BITFIELD_TEST_(offset,length) ( \
0 < length && length < 8 && offset%8 +length <= 8 || \
offset%8 == 0 && length%8 == 0 && 0 < length && length <= 32 \
)
#define STRINGIZE(m) #m
u32
(ACM_BITFIELD)( u8 a[], unsigned o, unsigned n ){
unsigned b = o/8;
return
n < 8 ? a[ o/8 ] >> (8 - o%8 - n) & ~(-1u << n) :
n == 32 ? a[b]*16777216u + a[b+1]*65536u + a[b+2]*256u + a[b+3] :
n == 24 ? a[b]*65536u + a[b+1]*256u + a[b+2] :
n == 16 ? a[b]*256u + a[b+1] :
/*****/ a[b];
}