Suppose I have the following simplified program:
Link to godbolt.org:
#include <cassert>
struct Dimensions {
Dimensions& operator=(int i) {
assert(i != 0);
return *this;
}
};
int getDim();
int main() {
Dimensions dims;
dims = getDim();//ok, just use runtime assert
dims = 0;//compile error wanted here
return 0;
}
In the first case (getDim
), it's not possible to check compile-time so we are happy to just check it at runtime.
But is it somehow possible to detect at compile as well (for the second case, dims = 0;
), when in theory it looks like it could be possible ? (perhaps with some kind of overloading or wrapper even ?)
Compile time is the period when the programming code (such as C#, Java, C, Python) is converted to the machine code (i.e. binary code). Runtime is the period of time when a program is running and generally occurs after compile time.
Compile-time and Runtime are the two programming terms used in the software development. Compile-time is the time at which the source code is converted into an executable code while the run time is the time at which the executable code is started running.
A compile-time error generally refers to the errors that correspond to the semantics or syntax. A runtime error refers to the error that we encounter during the code execution during runtime. We can easily fix a compile-time error during the development of code. A compiler cannot identify a runtime error.
Basically if your compiler can work out what you mean or what a value is "at compile time" it can hardcode this into the runtime code. Obviously if your runtime code has to do a calculation every time it will run slower, so if you can determine something at compile time it is much better.
A typical way to do in C with gcc compiler, that will also work in C++: you use __builtin_constant_p
builtin to check if an expression is a constantly evaluated and then check the expression and then call a function declared with a __attribute__((__warning__))
or with __attribute__((__error__))
. Like so:
#include <cassert>
#include <type_traits>
#define CONCAT(a, b) a ## b
#define XCONCAT(a, b) CONCAT(a, b)
#define maybe_static_maybe_not_assert(expr) do { \
if (__builtin_constant_p(expr)) { \
if (!(expr)) { \
extern __attribute__((__warning__( \
"static_assert: expression: " #expr " will fail on runtime!" \
))) void XCONCAT(maybe_static_maybe_not_assert_warn, __LINE__)(); \
XCONCAT(maybe_static_maybe_not_assert_warn, __LINE__)(); \
} \
} \
assert(expr); \
} while(0)
struct Dimensions {
Dimensions& operator=(int i) {
maybe_static_maybe_not_assert(i != 0);
return *this;
}
};
int getDim();
int main() {
Dimensions dims;
dims = getDim();
dims = 0;
dims = 1;
return 0;
}
It should issue a warning when compiled with optimizations:
In member function 'Dimensions& Dimensions::operator=(int)',
inlined from 'int main()' at <source>:32:12:
<source>:12:70: warning: call to 'maybe_static_maybe_not_assert_warn21' declared with attribute warning: static_assert: expression: i != 0 will fail on runtime! [-Wattribute-warning]
12 | XCONCAT(maybe_static_maybe_not_assert_warn, __LINE__)(); \
| ^
<source>:21:9: note: in expansion of macro 'maybe_static_maybe_not_assert'
21 | maybe_static_maybe_not_assert(i != 0);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compiler returned: 0
This is the way _FORTIFY_SOURCE
is implemented in glibc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With