3 ms·
> I have a small program which uses an undefined behavior. How would you rewrite this so as to not do so, but maintain all existing defined behaviors? in this
by jcelerier 8y ago
> I have a small program which uses an undefined behavior. How would you rewrite this so as to not do so, but maintain all existing defined behaviors?
in this precise case, (in C++ because I can't be arsed to search the modifier for int64), fairly easily :
#include <fmt.h>
#include <cstdio>
int main() {
int a{}, b{};
int64_t c{};
fmt::print("Please enter two numbers: ");
scanf("%d %d", &a, &b);
c = a + b;
fmt::printf("The sum of the numbers you entered is {}\n", c);
return 0;
}
in the case where a, b, were also of the largest int type available, you could do :
#include <stdio.h>
int main() {
int a, b, c;
printf("Please enter two numbers: ");
scanf("%d %d", &a, &b);
if(__builtin_add_overflow(a, b, &c))
{
printf("The sum of the numbers you entered is %d\n", c);
}
else
{
printf("You are in a twisty maze of compiler features, all different");
exec("/usr/bin/0ad");
}
return 0;
}
but you could also use the more portable macros provided in emacs (100 % independent of any other code) : https://github.com/jwiegley/emacs-release/blob/adfd5933358fdf6715423dee8169eb3cd7d982db/lib/intprops.h https://github.com/jwiegley/emacs-release/blob/adfd5933358fd...
- SloopJon 8y agoJohn Regehr wrote a post about checking for signed overflow a few years ago: https://blog.regehr.org/archives/1139 https://blog.regehr.org/archives/1139 HN discussion: https://news.ycombinator.com/item?id=7665254 https://news.ycombinator.com/item?id=7665254 Your first suggestion is similar to his checked_add_1(). The Emacs macros are similar to his checked_add_4(). Presumably builtins are optimal, performance wise, for a given compiler.
- mannykannot 8y agoWith regard to your first version: I had this vague feeling that the usual arithmetic conversions state that if the operands are of the same type, then no conversion is performed, and apparently this is so. If so, then would not the expression a + b potentially overflow, regardless of what it is being assigned to? FWIW, I tried this example: #include <stdio.h> #include <limits.h> #include <stdint.h> int main () { int64_t x; int a = INT_MAX, b = 1; x = a + b; printf( "%lu %lu %d %lld\n", sizeof(x), sizeof(a), a, x); return 0; } After compiling gcc -std=c11 -fsanitize=undefined -Wall -Wpedantic -Wextra (getting no warnings), on running I get c-undef.c:8:9: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' 8 4 2147483647 -2147483648 Also with -O0 and -O3. At least according to the answer in [1], signed (but not unsigned) integer overflow is undefined behavior (unless C and C++ have diverged on this matter, but I get the same result when the same source code is compiled as C++17.) This may seem to be pedantic (if it is not just wrong), but the point is that you have to be unremittingly pedantic to avoid undefined behavior. [1]https://stackoverflow.com/questions/16188263/is-signed-integer-overflow-still-undefined-behavior-in-c https://stackoverflow.com/questions/16188263/is-signed-integ...
- jcelerier 8y ago> I had this vague feeling that the usual arithmetic conversions state that if the operands are of the same type, then no conversion is performed that's 100% correct, nice catch.
- chowells 8y agoI like the idea of your first try, but it's not guaranteed to work on all implementations, even with the type promotion fixed. The problem is that the C standard doesn't specify a maximum size for int. It could be a 128 bit type. "Portable C" doesn't exist.
- jcelerier 8y ago> I like the idea of your first try, but it's not guaranteed to work on all implementations, in C++ you'd just add static_assert(sizeof(int) < sizeof(int64_t), "fix your types"); to be safe about this