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.)
Thanks!
On 13/07/2024 15:04, Alan Mackenzie wrote:
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.)
Thanks!
C does not have a way to force checks for this kind of thing at compile
time. But if you are using an optimising compiler, you can perhaps rely
on dead-code elimination along with link-time checks.
For example, declare a function "compile_time_error()" but do not define
it anywhere. Then add a check :
if (length > 8) compile_time_error();
As long as your check is not too complicated in relation to your
compiler's optimisation abilities, if it knows the value of "length" at compile time it and can see it is no more than 8, the call to compile_time_error() will be eliminated. If not, the call will be kept
and your link will fail as the function does not exist.
If you are using gcc (or, I expect, clang), you can go further.
First, define the compile_time_error() function with an error attribute:
extern void __attribute__((error("Compile time error"))) compile_time_error(void);
Then if the call is not eliminated, you will get an error message at
compile time rather than waiting for link time.
Add a "__attribute__((always_inline))" attribute to your bitfield
function - if it is used in a context that is not inlined, that will
show up as an error.
You might also find the gcc built-in function __builtin_constant_p(...) useful to determine if an expression value is known at compile time, in
case you want to add run-time checking for complex cases.
On 7/13/24 1:05 PM, Alan Mackenzie wrote:
Hello, David.
Many thanks for the reply! It's just what I was looking for.
David Brown <david.brown@hesbynett.no> wrote:
On 13/07/2024 15:04, Alan Mackenzie wrote:
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.)
Thanks!
C does not have a way to force checks for this kind of thing at compile
time. But if you are using an optimising compiler, you can perhaps rely >>> on dead-code elimination along with link-time checks.
For example, declare a function "compile_time_error()" but do not define >>> it anywhere. Then add a check :
if (length > 8) compile_time_error();
As long as your check is not too complicated in relation to your
compiler's optimisation abilities, if it knows the value of "length" at
compile time it and can see it is no more than 8, the call to
compile_time_error() will be eliminated. If not, the call will be kept
and your link will fail as the function does not exist.
This might be the way to go. The number of erroneous calls to
ACM_BITFIELD is expected to be low. The check is just there to make it
difficult for the optimisations in the function to create nonsense. But
if there are ~30 calls to the function, it would then be difficult to
located the erroneous one. So, perhaps ....
If you are using gcc (or, I expect, clang), you can go further.
First, define the compile_time_error() function with an error attribute:
extern void __attribute__((error("Compile time error")))
compile_time_error(void);
Then if the call is not eliminated, you will get an error message at
compile time rather than waiting for link time.
Add a "__attribute__((always_inline))" attribute to your bitfield
function - if it is used in a context that is not inlined, that will
show up as an error.
You might also find the gcc built-in function __builtin_constant_p(...)
useful to determine if an expression value is known at compile time, in
case you want to add run-time checking for complex cases.
Thanks, these are all things I didn't know. I will look them up in the
GCC manual. :-)
In C++, I would use constexpr and static_assert to do this, and your
compiler might allow its use in C as an extension.
If not, in C you could use just _Static_assert, perhaps in the expansion
of a macro that generates the expression that does the testing.
Hello, David.
Many thanks for the reply! It's just what I was looking for.
David Brown <david.brown@hesbynett.no> wrote:
On 13/07/2024 15:04, Alan Mackenzie wrote:
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.)
Thanks!
C does not have a way to force checks for this kind of thing at compile
time. But if you are using an optimising compiler, you can perhaps rely
on dead-code elimination along with link-time checks.
For example, declare a function "compile_time_error()" but do not define
it anywhere. Then add a check :
if (length > 8) compile_time_error();
As long as your check is not too complicated in relation to your
compiler's optimisation abilities, if it knows the value of "length" at
compile time it and can see it is no more than 8, the call to
compile_time_error() will be eliminated. If not, the call will be kept
and your link will fail as the function does not exist.
This might be the way to go. The number of erroneous calls to
ACM_BITFIELD is expected to be low. The check is just there to make it difficult for the optimisations in the function to create nonsense. But
if there are ~30 calls to the function, it would then be difficult to
located the erroneous one. So, perhaps ....
If you are using gcc (or, I expect, clang), you can go further.
First, define the compile_time_error() function with an error attribute:
extern void __attribute__((error("Compile time error")))
compile_time_error(void);
Then if the call is not eliminated, you will get an error message at
compile time rather than waiting for link time.
Add a "__attribute__((always_inline))" attribute to your bitfield
function - if it is used in a context that is not inlined, that will
show up as an error.
You might also find the gcc built-in function __builtin_constant_p(...)
useful to determine if an expression value is known at compile time, in
case you want to add run-time checking for complex cases.
Thanks, these are all things I didn't know. I will look them up in the
GCC manual. :-)
Hello, Richard.
Richard Damon <richard@damon-family.org> wrote:
On 7/13/24 1:05 PM, Alan Mackenzie wrote:
Hello, David.
Many thanks for the reply! It's just what I was looking for.
David Brown <david.brown@hesbynett.no> wrote:
On 13/07/2024 15:04, Alan Mackenzie wrote:
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.)
Thanks!
C does not have a way to force checks for this kind of thing at compile >>>> time. But if you are using an optimising compiler, you can perhaps rely >>>> on dead-code elimination along with link-time checks.
For example, declare a function "compile_time_error()" but do not define >>>> it anywhere. Then add a check :
if (length > 8) compile_time_error();
As long as your check is not too complicated in relation to your
compiler's optimisation abilities, if it knows the value of "length" at >>>> compile time it and can see it is no more than 8, the call to
compile_time_error() will be eliminated. If not, the call will be kept >>>> and your link will fail as the function does not exist.
This might be the way to go. The number of erroneous calls to
ACM_BITFIELD is expected to be low. The check is just there to make it
difficult for the optimisations in the function to create nonsense. But >>> if there are ~30 calls to the function, it would then be difficult to
located the erroneous one. So, perhaps ....
If you are using gcc (or, I expect, clang), you can go further.
First, define the compile_time_error() function with an error attribute:
extern void __attribute__((error("Compile time error")))
compile_time_error(void);
Then if the call is not eliminated, you will get an error message at
compile time rather than waiting for link time.
Add a "__attribute__((always_inline))" attribute to your bitfield
function - if it is used in a context that is not inlined, that will
show up as an error.
You might also find the gcc built-in function __builtin_constant_p(...) >>>> useful to determine if an expression value is known at compile time, in >>>> case you want to add run-time checking for complex cases.
Thanks, these are all things I didn't know. I will look them up in the
GCC manual. :-)
In C++, I would use constexpr and static_assert to do this, and your
compiler might allow its use in C as an extension.
C++ isn't an option.
If not, in C you could use just _Static_assert, perhaps in the expansion
of a macro that generates the expression that does the testing.
Yes, that's an even better idea, thanks. Looking it up in https://en.cppreference.com, _Static_assert has existed in C since C11,
that spelling being deprecated in favour of static_assert in C23. I just need to check the project I'm working in doesn't still support C < C11.
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.)
C++ isn't an option.
The question being since most C compilers are also C++ compilers, they >somethings accept this sort of C++ism as an extension.
On 7/13/24 1:05 PM, Alan Mackenzie wrote:
Hello, David.
Many thanks for the reply! It's just what I was looking for.
David Brown <david.brown@hesbynett.no> wrote:
On 13/07/2024 15:04, Alan Mackenzie wrote:
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.)
Thanks!
C does not have a way to force checks for this kind of thing at compile
time. But if you are using an optimising compiler, you can perhaps rely >>> on dead-code elimination along with link-time checks.
For example, declare a function "compile_time_error()" but do not define >>> it anywhere. Then add a check :
if (length > 8) compile_time_error();
As long as your check is not too complicated in relation to your
compiler's optimisation abilities, if it knows the value of "length" at
compile time it and can see it is no more than 8, the call to
compile_time_error() will be eliminated. If not, the call will be kept >>> and your link will fail as the function does not exist.
This might be the way to go. The number of erroneous calls to
ACM_BITFIELD is expected to be low. The check is just there to make it
difficult for the optimisations in the function to create nonsense. But
if there are ~30 calls to the function, it would then be difficult to
located the erroneous one. So, perhaps ....
If you are using gcc (or, I expect, clang), you can go further.
First, define the compile_time_error() function with an error attribute:
extern void __attribute__((error("Compile time error")))
compile_time_error(void);
Then if the call is not eliminated, you will get an error message at
compile time rather than waiting for link time.
Add a "__attribute__((always_inline))" attribute to your bitfield
function - if it is used in a context that is not inlined, that will
show up as an error.
You might also find the gcc built-in function __builtin_constant_p(...)
useful to determine if an expression value is known at compile time, in
case you want to add run-time checking for complex cases.
Thanks, these are all things I didn't know. I will look them up in the
GCC manual. :-)
In C++, I would use constexpr and static_assert to do this, and your
compiler might allow its use in C as an extension.
If not, in C you could use just _Static_assert, perhaps in the expansion
of a macro that generates the expression that does the testing.
On 7/13/24 1:56 PM, Alan Mackenzie wrote:
Hello, Richard.
Richard Damon <richard@damon-family.org> wrote:
On 7/13/24 1:05 PM, Alan Mackenzie wrote:
Hello, David.
Many thanks for the reply! It's just what I was looking for.
David Brown <david.brown@hesbynett.no> wrote:
On 13/07/2024 15:04, Alan Mackenzie wrote:
Hello, comp.lang.c.
Thanks, these are all things I didn't know. I will look them up in the >>>> GCC manual. :-)
In C++, I would use constexpr and static_assert to do this, and your
compiler might allow its use in C as an extension.
C++ isn't an option.
The question being since most C compilers are also C++ compilers, they somethings accept this sort of C++ism as an extension.
If not, in C you could use just _Static_assert, perhaps in the expansion >>> of a macro that generates the expression that does the testing.
Yes, that's an even better idea, thanks. Looking it up in
https://en.cppreference.com, _Static_assert has existed in C since C11,
that spelling being deprecated in favour of static_assert in C23. I just >> need to check the project I'm working in doesn't still support C < C11.
If the compiler doesn't support some form of static assert, you cam make
one yourself with a macro.
#define static_assert(x) extern int _static_assert[(x) ? 1 : -1]
Possible adding whatever hacks you want to make the variable unique, (or
make it a typedef, or whatever). (a typedef doesn't add an external
symbol that is never used, so might be clearer, but needs something to
make the name unique)
The key idea is a array of negative size is a constraint error, so if x
is false you get the error.
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];
}
David Brown <david.brown@hesbynett.no> writes:
On 13/07/2024 20:07, Richard Damon wrote:[...]
The question being since most C compilers are also C++ compilers,
they somethings accept this sort of C++ism as an extension.
Actually, the vast majority of C compilers are /not/ also C++
compilers. But the most popular C compilers, by a significant
margin, are C++ compilers.
I wouldn't quite put it that way.
gcc, clang, and Microsoft provide both C and C++ compilers, but they're separate applications, perhaps invoked from a common driver program.
They typically share the same backend, but the frontends are separate.
I wouldn't expect to see any code that parses "int class;" and decides whether it's a syntax error based on which language is being compiled.
The C and C++ frontends might share some code, but they're separate applications.
I wanted to generate code conditionally, depending on the macro's
arguments, for efficiency's sake. I don't think this is possible - the C preprocessor is not Lisp. What I missed was that the compiler's
optimizer will eliminate the superfluous code anyway, so it doesn't
really matter.
Hello, Tim.
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
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.
I wanted to generate code conditionally, depending on the macro's
arguments, for efficiency's sake. I don't think this is possible - the C preprocessor is not Lisp. What I missed was that the compiler's
optimizer will eliminate the superfluous code anyway, so it doesn't
really matter.
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.)
_Static_assert will only work within a macro. It doesn't work in an
inline function, whose parameters are not constant expressions, despite
being constants known at compile time. I like the way you've got around this, below.
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.
Thanks. I'll probably use something like that after my attempts last
night failed. Just that the byte order needs to be little-endian rather
than big-endian. Having unsigned parameters indeed makes sense, seeing
as how it eliminates trouble with negative lengths and offsets.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 546 |
Nodes: | 16 (0 / 16) |
Uptime: | 156:23:09 |
Calls: | 10,384 |
Calls today: | 1 |
Files: | 14,056 |
Messages: | 6,416,469 |