Path: ...!weretis.net!feeder9.news.weretis.net!i2pn.org!i2pn2.org!.POSTED!not-for-mail From: Richard Damon Newsgroups: comp.lang.c Subject: Re: Is it possible to generate a compile time error from an inline function? Date: Sat, 13 Jul 2024 13:34:35 -0400 Organization: i2pn2 (i2pn.org) Message-ID: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Sat, 13 Jul 2024 17:34:35 -0000 (UTC) Injection-Info: i2pn2.org; logging-data="3137774"; mail-complaints-to="usenet@i2pn2.org"; posting-account="diqKR1lalukngNWEqoq9/uFtbkm5U+w3w6FQ0yesrXg"; User-Agent: Mozilla Thunderbird X-Spam-Checker-Version: SpamAssassin 4.0.0 In-Reply-To: Content-Language: en-US Bytes: 4599 Lines: 86 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 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.