im new with c language, but i try to unerstand this quark hashing algorithm that was written in c language, and i found an error while im compiling the source code, from what i understand the WIDTH it already declared, but why is it still error ?
this is the source code
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
/* uncomment to printf execution traces */
// #define DEBUG
#if defined(UQUARK)
#define CAPACITY 16
#define RATE 1
#define WIDTH 17
#elif defined(DQUARK)
#define CAPACITY 20
#define RATE 2
#define WIDTH 22
#endif
#define DIGEST WIDTH
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint8_t u8;
typedef struct {
int pos; /* number of bytes read into x from current block */
// u32 x[ WIDTH*8 ]; /* one bit stored in each word */
u32 x[ WIDTH*8 ]; /* one bit stored in each word */
} hashState;
#if defined(UQUARK)
/* 17 bytes */
u8 iv[] = {0xd8,0xda,0xca,0x44,0x41,0x4a,0x09,0x97,
0x19,0xc8,0x0a,0xa3,0xaf,0x06,0x56,0x44,0xdb};
and its showing this error
quark.c:36:10: error : 'WIDTH' undeclared here (not in a function)
u32 x[WIDTH*8];
I guess for some reason neither UQUARK nor DQUARK are defined.
Add this:
#if defined(UQUARK) && defined(DQUARK)
#error both UQUARK and DQUARK are defined
#endif
#if !defined(UQUARK) && !defined(dQUARK)
#error Neither UQUARK nor DQUARK are defined
#endif
just before following line:
#if defined(UQUARK)
Then the compilation will abort if either both UQUARK and DQUARK are defined (which probably makes no sense) or if neither UQUARK nor DQUARK are defined (which probably happens in your case).
Now the question is: who defines UQUARK and/or DQUARK? Only you can tell.
Related
I am working on a library to read Serial data from an electric counter. The counter can transmit up to 105 different tags depending on your contract. Because this library could be on lightweight and not powerful embedded systems (typically arduino or esp8266), I am trying to reduce the memory usage to the bare minimum.
To read each tag, my library has a buffer with its length equal the biggest tag value length possible (ranging from 2 bytes to 94 bytes). I would like my library to automatically set the buffer size to the correct value kowning that the user is able to indicate which tag he wants with #define instructions in its main file.
main.cpp
#define BASE
#define HCHP
#define OPTARIF
#include "LinkyTIC.h"
#include <SoftwareSerial.h>
SoftwareSerial LinkySerial(13, 15);
LinkyTIC linky(LinkySerial);
void setup() {
}
void loop() {
if(linky.read()){
int base = linky.GetBASE();
int hchp = linky.GetHCHP();
Serial.println(base);
Serial.println(hchp);
}
}
What I tried :
In my header file, I used a chain of #ifdef to keep the maximum length, but I get the error "the value of variable "max_length" cannot be used as a constant". I tried to cast the value to a constant but it didn't work either.
header.h
uint8_t max_length = 8;
#ifdef ADCO
uint8_t max_length = max_length > 12 ? max_length : 12;
#endif
#ifdef OPTARIF
uint8_t max_length = max_length > 4 ? max_length : 4;
#endif
#ifdef ISOUSC
uint8_t max_length = max_length > 2 ? max_length : 2;
#endif
#ifdef BASE
uint8_t max_length = max_length > 9 ? max_length : 9;
#endif
...
class LinkyTIC {
public:
// unrelated stuff
private:
// unrelated stuff
char _buffer_tag[8]; // buffer for the tag name
>>>> char _buffer_date[max_length]; // buffer for the (optional) tag date. Must be the same length as value because we can't know in advance if it s going to be a date or a value
^^^^^^^^^^ the value of variable "max_length" cannot be used as a constant
>>>> char _buffer_value[max_length]; // buffer for the tag value
^^^^^^^^^^ the value of variable "max_length" cannot be used as a constant
char _buffer_checksum[1]; // buffer for the tag checksum
char _checksum;
char* _buffers[4] = {_buffer_tag, _buffer_date, _buffer_value, _buffer_checksum};
uint8_t _buffer_reference_index;
uint8_t _buffer_index;
...
}
The value of max_length can thus be known at compile time, but I can't figure out a way to create my array using its value.
What would be the best way to achieve what I want to do ? Because flash is also an issue, I would rather avoid using std::vector.
There are a number of options using preprocessor macros and #if statements, depending on what your requirements are, which you have not clearly stated. One example is:
#define MaximumLength 8
#if defined ADCO
#if MaximumLength > 12
#undef MaximumLength
#define MaximumLength 12
#endif
#endif
#if defined OPTARIF
#if MaximumLength > 4
#undef MaximumLength
#define MaximumLength 4
#endif
#endif
#if defined ISOUSC
#if MaximumLength > 2
#undef MaximumLength
#define MaximumLength 2
#endif
#endif
#if defined BASE
#if MaximumLength > 9
#undef MaximumLength
#define MaximumLength 9
#endif
#endif
uint8_t max_length = MaximumLength; // If this variable is still desired.
…
char _buffer_date[MaximumLength];
First of all you need to define your variable either const or consexpr.
Since you code already has error, you can't redefine variable with same name, I'm not sure what you intended to do, but something like this should work:
#include <cstdint>
#include <iostream>
#include <algorithm>
// Uncomment line(s) below to check behavior
//#define ADCO
//#define OPTARIF
//#define ISOUSC
//#define BASE
const uint8_t def_max_length = 8;
#ifdef ADCO
const uint8_t max_length = std::max<uint8_t>(def_max_length, 12);
#elif defined(OPTARIF)
const uint8_t max_length = std::max<uint8_t>(def_max_length, 4);
#elif defined(ISOUSC)
const uint8_t max_length = std::max<uint8_t>(def_max_length, 2);
#elif defined(BASE)
const uint8_t max_length = std::max<uint8_t>(def_max_length, 9);
#else
const uint8_t max_length = def_max_length;
#endif
char buffer[max_length];
int main()
{
std::cout << std::size(buffer) << std::endl;
}
If you need to check all defines independently, then you can define one variable for each define, something like:
#ifdef ADCO
const uint8_t max_length_adco = 12;
#else
const uint8_t max_length_adco = 0;
#ednif
And then just get maximum of all these variables:
const uint8_t max_length = std::max({def_max_length, max_length_adco, max_length_optarif, max_length_isousc, max_length_base});
I have written an amazing kernel which will bring me fame and fortune - if I can only get it to compile with NVRTC:
#include <stdio.h>
__global__ void do_stuff() { }
I would have hoped that system headers should be recognized by the (runtime) compiler, just like a regular compiler, and that this would "just work" (modulo any printf-specific machinery). Alternatively, if it didn't work, I would have expected an error message about stdio.h's source not made available with the "program creation" API call (nvrtcCreateProgram()), since I'm passing NULL and NULL as its last two arguments.
However, what I get is the following:
/usr/include/stdio.h(33): catastrophic error: cannot open source file "stddef.h"
This seems strange to me. It means that the runtime compiler is able to look inside system headers, but is not able to find stddef.h, like nvcc or the host side compiler are able to.
Why is this happening, and what is the idiomatic/recommended workaround?
Note: I'd like a workaround which would be cross-platform, not just work on my individual machine.
Here are two solutions which might work, but which I would rather avoid. If they're the only reasonable course of action after all - please comment and say so:
Add the specific path to stddef.h as a compiler parameter (-I or --include-path=).
Pass the source of stddef.h to the nvrtcCreateProgram() call.
An additional approach is taken in the "JITify" library which Robert Crovella has graciously reminded me of. While this doesn't seem to be document very well, Jitify pre-includes processed snippets of various headers it sees fit to. In particular for <climits>/<limits.h>:
static const char* jitsafe_header_limits_h = R"(
#pragma once
#if defined _WIN32 || defined _WIN64
#define __WORDSIZE 32
#else
#if defined __x86_64__ && !defined __ILP32__
#define __WORDSIZE 64
#else
#define __WORDSIZE 32
#endif
#endif
#define MB_LEN_MAX 16
#define CHAR_BIT 8
#define SCHAR_MIN (-128)
#define SCHAR_MAX 127
#define UCHAR_MAX 255
enum {
_JITIFY_CHAR_IS_UNSIGNED = (char)-1 >= 0,
CHAR_MIN = _JITIFY_CHAR_IS_UNSIGNED ? 0 : SCHAR_MIN,
CHAR_MAX = _JITIFY_CHAR_IS_UNSIGNED ? UCHAR_MAX : SCHAR_MAX,
};
#define SHRT_MIN (-32768)
#define SHRT_MAX 32767
#define USHRT_MAX 65535
#define INT_MIN (-INT_MAX - 1)
#define INT_MAX 2147483647
#define UINT_MAX 4294967295U
#if __WORDSIZE == 64
# define LONG_MAX 9223372036854775807L
#else
# define LONG_MAX 2147483647L
#endif
#define LONG_MIN (-LONG_MAX - 1L)
#if __WORDSIZE == 64
#define ULONG_MAX 18446744073709551615UL
#else
#define ULONG_MAX 4294967295UL
#endif
#define LLONG_MAX 9223372036854775807LL
#define LLONG_MIN (-LLONG_MAX - 1LL)
#define ULLONG_MAX 18446744073709551615ULL
)";
for stddef.h:
static const char* jitsafe_header_stddef_h =
"#pragma once\n"
"#include <climits>\n"
"namespace __jitify_stddef_ns {\n"
"#if __cplusplus >= 201103L\n"
"typedef decltype(nullptr) nullptr_t;\n"
"#if defined(_MSC_VER)\n"
" typedef double max_align_t;\n"
"#elif defined(__APPLE__)\n"
" typedef long double max_align_t;\n"
"#else\n"
" // Define max_align_t to match the GCC definition.\n"
" typedef struct {\n"
" long long __jitify_max_align_nonce1\n"
" __attribute__((__aligned__(__alignof__(long long))));\n"
" long double __jitify_max_align_nonce2\n"
" __attribute__((__aligned__(__alignof__(long double))));\n"
" } max_align_t;\n"
"#endif\n"
"#endif // __cplusplus >= 201103L\n"
"#if __cplusplus >= 201703L\n"
"enum class byte : unsigned char {};\n"
"#endif // __cplusplus >= 201703L\n"
"} // namespace __jitify_stddef_ns\n"
"namespace std {\n"
" // NVRTC provides built-in definitions of ::size_t and ::ptrdiff_t.\n"
" using ::size_t;\n"
" using ::ptrdiff_t;\n"
" using namespace __jitify_stddef_ns;\n"
"} // namespace std\n"
"using namespace __jitify_stddef_ns;\n";
and for stdio.h:
static const char* jitsafe_header_stdio_h =
"#pragma once\n"
"#include <stddef.h>\n"
"#define FILE int\n"
"int fflush ( FILE * stream );\n"
"int fprintf ( FILE * stream, const char * format, ... );\n";
If you include those strings as headers, with the appropriate names as keys, it is likely your kernel will compile.
In fact, one could form header files out of these and other mini-headers in jitify.hpp, to use in non-NVRTC kernel compilation. That might be useful too.
One last point: The constants above do not specify a __device__ execution space. So, either you add __device__ in there, or tell the compiler to assume functions are intended for execution on the device only, unless otherwise specified; that's the --device-as-default-execution-space NVRTC compiler option.
I'm trying to write definitions for AVR C code so that i can access pins by simmple macro like
STATUS_LED_OUT =1;
in GENET_HW_DEF.h file, included to main C file. You can reproduce this bug by including this file into any C project.
I'm using avr studio 6.2 and 7 - both give the same result. I cannot compile getting werid macro unfold message like below. (CPU ATMega1284p)
D:\_SVN\Compass\AVR\Compass_IO_proto\Compass IO_proto\GENET_HW_DEF.h(19,49): error: expected ')' before '&' token
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt
^
D:\_SVN\Compass\AVR\Compass_IO_proto\Compass IO_proto\GENET_HW_DEF.h(42,25): info: in expansion of macro 'REGISTER_BIT'
#define STATUS_LED_OUT REGISTER_BIT(PORTB,7)
^
D:\_SVN\Compass\AVR\Compass_IO_proto\Compass IO_proto\GENET_HW_DEF.h(46,2): info: in expansion of macro 'STATUS_LED_OUT'
STATUS_LED_OUT=1;
^
Interesting enough, copied to fresh project with just only one or two declarations compiles fine, until one makes any changes in the declarations - like adding another macro reference. Then it becomes stuck again.
Also - if i comment all macro usages like
STATUS_LED_DIR=1;
STATUS_LED_OUT=1;
then I'm able to compile project and then after uncommenting usage lines it still compiles fine.. untill clean is executed. I'm probably messing with macro quirks but I have no idea where.
typedef struct
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
unsigned int bit4:1;
unsigned int bit5:1;
unsigned int bit6:1;
unsigned int bit7:1;
} _io_reg;
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt
#ifndef GENET_HW_DEF
#define GENET_HW_DEF
// define functionalities and flags - comment/uncomment apropriate lines
#define GENET_USART_0 256
#define GENET_USART_1 256
#define F_CPU 20000000UL
#define STATUS_LED 7
#define ERROR_LED 4
#define ADC_GLOBAL_ENABLE A
#define ADC_CHANNEL_0 0
#define ADC_CHANNEL_1 4
#define ADC_CHANNEL_2 2
#define ADC_CHANNEL_3 3
#define ADC_CHANNEL_4 1
#define ADC_CHANNEL_5 5
#define ADC_CHANNEL_6 6
#define ADC_CHANNEL_7 7
// actual definitions and initialization
#ifdef STATUS_LED
#define STATUS_LED_OUT REGISTER_BIT(PORTB,STATUS_LED)
#define STATUS_LED_DIR REGISTER_BIT(DDRB,STATUS_LED)
#define STATUS_LED_PIN REGISTER_BIT(PINB,STATUS_LED)
STATUS_LED_DIR=1;
STATUS_LED_OUT=1;
#endif
#ifdef ERROR_LED
#define ERROR_LED_OUT REGISTER_BIT(PORTC,ERROR_LED)
#define ERROR_LED_DIR REGISTER_BIT(DDRC,ERROR_LED)
ERROR_LED_DIR=1;
ERROR_LED_OUT=1;
#endif
#ifdef GENET_USART_0
#define USART0_ENABLED
#define UART_RX0_BUFFER_SIZE GENET_USART_0
#define UART_TX0_BUFFER_SIZE GENET_USART_0
#endif
#ifdef GENET_USART_1
#define USART1_ENABLED
#define UART_RX1_BUFFER_SIZE GENET_USART_1
#define UART_TX1_BUFFER_SIZE GENET_USART_1
#endif
#endif
I reproduced your problem.
You cannot call STATUS_LED_DIR=1; outside code execution flow. This must be inside a function (for example main()).
Now you will end with other compilation errors but this was the main mistake.
Second correction, you need 2 level for concatenation
#define CONCAT(bt) bit##bt
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->CONCAT(bt)
My compiler raises the warning #381-D: extra ";" ignored in such a situation:
I have a struct defined, like the following
struct example_s
{
u8_t foo;
SOME_MACRO(bar);
};
The macro SOME_MACRO(x) does the following:
#if defined(SYSTEM_A)
#define SOME_MACRO(x) u16_t x##something
#else
#define SOME_MACRO(x) /* nothing */
#endif
Of course, the warning is correct, when SYSTEM_A is not defined. Simply because I have now a ; within the struct. But does someone know a way to avoid it correctly? I don't want to break the typical C-style by moving the ; into the macro.
One way that is a bit of a kludge but it seems to work with gcc:
#if defined(SYSTEM_A)
#define SOME_MACRO(x) u16_t x##something
#else
#define SOME_MACRO(x) int x[0] /* nothing */
#endif
With this method you end up with a struct like this:
struct example_s
{
u8_t foo;
int bar[0];
};
which has the correct size (i.e. as size as if bar had not been defined at all).
You can add an unnamed 0-width bitfield instead:
#if defined(SYSTEM_A)
#define SOME_MACRO(x) u16_t x##something
#else
#define SOME_MACRO(x) unsigned :0
#endif
you can also insert an empty anonymous struct :
#if defined(SYSTEM_A)
#define SOME_MACRO(x) u16_t x##something
#else
#define SOME_MACRO(x) struct {}
#endif
I'm tidying up some older code that uses 'magic numbers' all over the place to set hardware registers, and I would like to use constants instead of these numbers to make the code somewhat more expressive (in fact they will map to the names/values used to document the registers).
However, I'm concerned that with the volume of changes I might break the magic numbers. Here is a simplified example (the register set is more complex):
const short mode0 = 0;
const short mode1 = 1;
const short mode2 = 2;
const short state0 = 0;
const short state1 = 4;
const short state2 = 8;
so instead of :
set_register(5);
we have:
set_register(state1|mode1);
What I'm looking for is a build time version of:
ASSERT(5==(state1|mode1));
Update
#Christian, thanks for the quick response, I'm interested on a C / non-boost environment answer too because this is driver/kernel code.
NEW ANSWER :
In my original answer (below), I had to have two different macros to support assertions in a function scope and at the global scope. I wondered if it was possible to come up with a single solution that would work in both scopes.
I was able to find a solution that worked for Visual Studio and Comeau compilers using extern character arrays. But I was able to find a more complex solution that works for GCC. But GCC's solution doesn't work for Visual Studio. :( But adding a '#ifdef __ GNUC __', it's easy to choose the right set of macros for a given compiler.
Solution:
#ifdef __GNUC__
#define STATIC_ASSERT_HELPER(expr, msg) \
(!!sizeof \ (struct { unsigned int STATIC_ASSERTION__##msg: (expr) ? 1 : -1; }))
#define STATIC_ASSERT(expr, msg) \
extern int (*assert_function__(void)) [STATIC_ASSERT_HELPER(expr, msg)]
#else
#define STATIC_ASSERT(expr, msg) \
extern char STATIC_ASSERTION__##msg[1]; \
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
#endif /* #ifdef __GNUC__ */
Here are the error messages reported for STATIC_ASSERT(1==1, test_message); at line 22 of test.c:
GCC:
line 22: error: negative width in bit-field `STATIC_ASSERTION__test_message'
Visual Studio:
test.c(22) : error C2369: 'STATIC_ASSERTION__test_message' : redefinition; different subscripts
test.c(22) : see declaration of 'STATIC_ASSERTION__test_message'
Comeau:
line 22: error: declaration is incompatible with
"char STATIC_ASSERTION__test_message[1]" (declared at line 22)
ORIGINAL ANSWER :
I do something very similar to what Checkers does. But I include a message that'll show up in many compilers:
#define STATIC_ASSERT(expr, msg) \
{ \
char STATIC_ASSERTION__##msg[(expr)?1:-1]; \
(void)STATIC_ASSERTION__##msg[0]; \
}
And for doing something at the global scope (outside a function) use this:
#define GLOBAL_STATIC_ASSERT(expr, msg) \
extern char STATIC_ASSERTION__##msg[1]; \
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
There is an article by
Ralf Holly that examines different options for static asserts in C.
He presents three different approaches:
switch case values must be unique
arrays must not have negative dimensions
division by zero for constant expressions
His conclusion for the best implementation is this:
#define assert_static(e) \
do { \
enum { assert_static__ = 1/(e) }; \
} while (0)
Checkout boost's static assert
You can roll your own static assert if you don't have access to a third-party library static assert function (like boost):
#define STATIC_ASSERT(x) \
do { \
const static char dummy[(x)?1:-1] = {0};\
} while(0)
The downside is, of course, that error message is not going to be very helpful, but at least, it will give you the line number.
#define static_assert(expr) \
int __static_assert(int static_assert_failed[(expr)?1:-1])
It can be used anywhere, any times.
I think it is the easiest solution.
Before usage, test it with your compiler carefully.
Any of the techniques listed here should work and when C++0x becomes available you will be able to use the built-in static_assert keyword.
If you have Boost then using BOOST_STATIC_ASSERT is the way to go. If you're using C or don't want to get Boost
here's my c_assert.h file that defines (and explains the workings of) a few macros to handle static assertions.
It's a bit more convoluted that it should be because in ANSI C code you need 2 different macros - one that can work in the area where you have declarations and one that can work in the area where normal statements go. There is a also a bit of work that goes into making the macro work at global scope or in block scope and a bunch of gunk to ensure that there are no name collisions.
STATIC_ASSERT() can be used in the variable declaration block or global scope.
STATIC_ASSERT_EX() can be among regular statements.
For C++ code (or C99 code that allow declarations mixed with statements) STATIC_ASSERT() will work anywhere.
/*
Define macros to allow compile-time assertions.
If the expression is false, an error something like
test.c(9) : error XXXXX: negative subscript
will be issued (the exact error and its format is dependent
on the compiler).
The techique used for C is to declare an extern (which can be used in
file or block scope) array with a size of 1 if the expr is TRUE and
a size of -1 if the expr is false (which will result in a compiler error).
A counter or line number is appended to the name to help make it unique.
Note that this is not a foolproof technique, but compilers are
supposed to accept multiple identical extern declarations anyway.
This technique doesn't work in all cases for C++ because extern declarations
are not permitted inside classes. To get a CPP_ASSERT(), there is an
implementation of something similar to Boost's BOOST_STATIC_ASSERT(). Boost's
approach uses template specialization; when expr evaluates to 1, a typedef
for the type
::interslice::StaticAssert_test< sizeof( ::interslice::StaticAssert_failed<true>) >
which boils down to
::interslice::StaticAssert_test< 1>
which boils down to
struct StaticAssert_test
is declared. If expr is 0, the compiler will be unable to find a specialization for
::interslice::StaticAssert_failed<false>.
STATIC_ASSERT() or C_ASSERT should work in either C or C++ code (and they do the same thing)
CPP_ASSERT is defined only for C++ code.
Since declarations can only occur at file scope or at the start of a block in
standard C, the C_ASSERT() or STATIC_ASSERT() macros will only work there. For situations
where you want to perform compile-time asserts elsewhere, use C_ASSERT_EX() or
STATIC_ASSERT_X() which wrap an enum declaration inside it's own block.
*/
#ifndef C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
#define C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
/* first some utility macros to paste a line number or counter to the end of an identifier
* this will let us have some chance of generating names that are unique
* there may be problems if a static assert ends up on the same line number in different headers
* to avoid that problem in C++ use namespaces
*/
#if !defined( PASTE)
#define PASTE2( x, y) x##y
#define PASTE( x, y) PASTE2( x, y)
#endif /* PASTE */
#if !defined( PASTE_LINE)
#define PASTE_LINE( x) PASTE( x, __LINE__)
#endif /* PASTE_LINE */
#if!defined( PASTE_COUNTER)
#if (_MSC_VER >= 1300) /* __COUNTER__ introduced in VS 7 (VS.NET 2002) */
#define PASTE_COUNTER( x) PASTE( x, __COUNTER__) /* __COUNTER__ is a an _MSC_VER >= 1300 non-Ansi extension */
#else
#define PASTE_COUNTER( x) PASTE( x, __LINE__) /* since there's no __COUNTER__ use __LINE__ as a more or less reasonable substitute */
#endif
#endif /* PASTE_COUNTER */
#if __cplusplus
extern "C++" { // required in case we're included inside an extern "C" block
namespace interslice {
template<bool b> struct StaticAssert_failed;
template<> struct StaticAssert_failed<true> { enum {val = 1 }; };
template<int x> struct StaticAssert_test { };
}
}
#define CPP_ASSERT( expr) typedef ::interslice::StaticAssert_test< sizeof( ::interslice::StaticAssert_failed< (bool) (expr) >) > PASTE_COUNTER( IntersliceStaticAssertType_)
#define STATIC_ASSERT( expr) CPP_ASSERT( expr)
#define STATIC_ASSERT_EX( expr) CPP_ASSERT( expr)
#else
#define C_ASSERT_STORAGE_CLASS extern /* change to typedef might be needed for some compilers? */
#define C_ASSERT_GUID 4964f7ac50fa4661a1377e4c17509495 /* used to make sure our extern name doesn't collide with something else */
#define STATIC_ASSERT( expr) C_ASSERT_STORAGE_CLASS char PASTE( PASTE( c_assert_, C_ASSERT_GUID), [(expr) ? 1 : -1])
#define STATIC_ASSERT_EX(expr) do { enum { c_assert__ = 1/((expr) ? 1 : 0) }; } while (0)
#endif /* __cplusplus */
#if !defined( C_ASSERT) /* C_ASSERT() might be defined by winnt.h */
#define C_ASSERT( expr) STATIC_ASSERT( expr)
#endif /* !defined( C_ASSERT) */
#define C_ASSERT_EX( expr) STATIC_ASSERT_EX( expr)
#ifdef TEST_IMPLEMENTATION
C_ASSERT( 1 < 2);
C_ASSERT( 1 < 2);
int main( )
{
C_ASSERT( 1 < 2);
C_ASSERT( 1 < 2);
int x;
x = 1 + 4;
C_ASSERT_EX( 1 < 2);
C_ASSERT_EX( 1 < 2);
return( 0);
}
#endif /* TEST_IMPLEMENTATION */
#endif /* C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546 */
Try:
#define STATIC_ASSERT(x, error) \
do { \
static const char error[(x)?1:-1];\
} while(0)
Then you can write:
STATIC_ASSERT(a == b, a_not_equal_to_b);
Which may give you a better error message (depending on your compiler).
The common, portable option is
#if 5 != (state1|mode1)
# error "aaugh!"
#endif
but it doesn't work in this case, because they're C constants and not #defines.
You can see the Linux kernel's BUILD_BUG_ON macro for something that handles your case:
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
When condition is true, this becomes ((void)sizeof(char[-1])), which is illegal and should fail at compile time, and otherwise it becomes ((void)sizeof(char[1])), which is just fine.
Ensure you compile with a sufficiently recent compiler (e.g. gcc -std=c11).
Then your statement is simply:
_Static_assert(state1|mode1 == 5, "Unexpected change of bitflags");
#define MODE0 0
#define MODE1 1
#define MODE2 2
#define STATE0 0
#define STATE1 4
#define STATE2 8
set_register(STATE1|STATE1); //set_register(5);
#if (!(5==(STATE1|STATE1))) //MY_ASSERT(5==(state1|mode1)); note the !
#error "error blah blah"
#endif
This is not as elegant as a one line MY_ASSERT(expr) solution. You could use sed, awk, or m4 macro processor before compiling your C code to generate the DEBUG code expansion of MY_ASSERT(expr) to multiple lines or NODEBUG code which removes them for production.