C: Make sure TRUE is equal to exactly 1 - c

I would like to sum over a number of bool variables to find out how many of them are TRUE. Since there is no real bool type in C (only int), I cannot be entirely sure that TRUE means exactly 1. It could theoretically be any integer greater than zero.
What is a computationally efficient and readable way to ensure this?
P.S. I am aware of this similar question. However, my case is slightly different, as the bool values don't come from an internal truth check, but from an external source (CAN signal).

Never use a _Bool (or bool defined by #include <stdbool.h>) if it is possible for the object to contain a value other than 0 or 1. The compiler is at liberty to assume the object will contain a value of 0 or 1 and produce unexpected results if it contains a different value. In particular, GCC tends to produce unexpected results from the following program:
foo.c
#include <stdio.h>
#include <string.h>
int main(void)
{
_Bool b;
memset(&b, 0xff, sizeof b);
printf("int = %d\n", (int)b);
printf("int_bool = %d\n", (int)(_Bool)b);
printf("int_bool_int = %d\n", (int)(_Bool)(int)b);
printf("int_not_not = %d\n", (int)!!b);
printf("not_not_int = %d\n", !!(int)b);
return 0;
}
On Debian GNU/Linux 11 x86_64:
$ gcc --version
gcc (Debian 10.2.1-6) 10.2.1 20210110
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gcc -O2 foo.c -o foo
$ ./foo
int = 255
int_bool = 255
int_bool_int = 255
int_not_not = 255
not_not_int = 255
One might have expected most of those printed values to be 1 rather than 255.

Related

Why does `gcc -ffast-math` disable the correct result of `isnan()` and `isinf()`?

I understand that using the -ffast-math flag allows for unsafe math operations and disables signalling NaNs. However, I expected the functions isnan() and isinf() to still be able to return the correct results, which they do not.
Here's an example:
File test_isnan.c:
#include <stdio.h>
#include <math.h>
int main(void){
/* Produce a NaN */
const float my_nan = sqrtf(-1.f);
/* Produce an inf */
const float my_inf = 1.f/0.f;
printf("This should be a NaN: %.6e\n", my_nan);
printf("This should be inf: %.6e\n", my_inf);
if (isnan(my_nan)) {
printf("Caugth the nan!\n");
} else {
printf("isnan failed?\n");
}
if (isinf(my_inf)) {
printf("Caugth the inf!\n");
} else {
printf("isinf failed?\n");
}
}
Now let's compile and run the program without -ffast-math:
$ gcc test_isnan.c -lm -o test_isnan.o && ./test_isnan.o
This should be a NaN: -nan
This should be inf: inf
Caugth the nan!
Caugth the inf!
But with it:
$ gcc test_isnan.c -lm -o test_isnan.o -ffast-math && ./test_isnan.o
This should be a NaN: -nan
This should be inf: inf
isnan failed?
isinf failed?
So why don't isnan() and isinf() catch these nans and infs? What am I missing?
In case it might be relevant, here's my gcc version:
gcc (Spack GCC) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
From https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html:
-ffast-math
Sets the options -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans, -fcx-limited-range and -fexcess-precision=fast.
Where:
-ffinite-math-only
Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs.
The moment you break that assumption, you can't expect those functions to work.
I understand that you were hoping for this setting to optimize all the other operations while still providing a correct result for these two functions, but that's just not the way it works. I don't think there's a way to solve this. Maybe you can have a look at Clang, but I don't expect it to be different.
-ffast-math
Sets the options ... -ffinite-math-only ...
-ffinite-math-only
Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs.
Compiler optimizes the code to:
printf("This should be a NaN: %.6e\n", sqrtf(-1.f));
printf("This should be inf: %.6e\n", 1.f/0.f);
printf("isnan failed?\n");
printf("isinf failed?\n");
because the compiler knows that expressions can't return nan or inf.

gcc's __builtin_memcpy performance with certain number of bytes is terrible compared to clang's

I thought I`d first share this here to have your opinions before doing anything else. I found out while designing an algorithm that the gcc compiled code performance for some simple code was catastrophic compared to clang's.
How to reproduce
Create a test.c file containing this code :
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
int main(int argc, char *argv[]) {
const uint64_t size = 1000000000;
const size_t alloc_mem = size * sizeof(uint8_t);
uint8_t *mem = (uint8_t*)malloc(alloc_mem);
for (uint_fast64_t i = 0; i < size; i++)
mem[i] = (uint8_t) (i >> 7);
uint8_t block = 0;
uint_fast64_t counter = 0;
uint64_t total = 0x123456789abcdefllu;
uint64_t receiver = 0;
for(block = 1; block <= 8; block ++) {
printf("%u ...\n", block);
counter = 0;
while (counter < size - 8) {
__builtin_memcpy(&receiver, &mem[counter], block);
receiver &= (0xffffffffffffffffllu >> (64 - ((block) << 3)));
total += ((receiver * 0x321654987cbafedllu) >> 48);
counter += block;
}
}
printf("=> %llu\n", total);
return EXIT_SUCCESS;
}
gcc
Compile and run :
gcc-7 -O3 test.c
time ./a.out
1 ...
2 ...
3 ...
4 ...
5 ...
6 ...
7 ...
8 ...
=> 82075168519762377
real 0m23.367s
user 0m22.634s
sys 0m0.495s
info :
gcc-7 -v
Using built-in specs.
COLLECT_GCC=gcc-7
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc/7.3.0/libexec/gcc/x86_64-apple-darwin17.4.0/7.3.0/lto-wrapper
Target: x86_64-apple-darwin17.4.0
Configured with: ../configure --build=x86_64-apple-darwin17.4.0 --prefix=/usr/local/Cellar/gcc/7.3.0 --libdir=/usr/local/Cellar/gcc/7.3.0/lib/gcc/7 --enable-languages=c,c++,objc,obj-c++,fortran --program-suffix=-7 --with-gmp=/usr/local/opt/gmp --with-mpfr=/usr/local/opt/mpfr --with-mpc=/usr/local/opt/libmpc --with-isl=/usr/local/opt/isl --with-system-zlib --enable-checking=release --with-pkgversion='Homebrew GCC 7.3.0' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --disable-nls
Thread model: posix
gcc version 7.3.0 (Homebrew GCC 7.3.0)
So we get about 23s of user time. Now let's do the same with cc (clang on macOS) :
clang
cc -O3 test.c
time ./a.out
1 ...
2 ...
3 ...
4 ...
5 ...
6 ...
7 ...
8 ...
=> 82075168519762377
real 0m9.832s
user 0m9.310s
sys 0m0.442s
info :
Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin17.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
That's more than 2.5x faster !! Any thoughts ?
I replaced the __builtin_memcpy function by memcpy to test things out and this time the compiled code runs in about 34s on both sides - consistent and slower as expected.
It would appear that the combination of __builtin_memcpy and bitmasking is interpreted very differently by both compilers.
I had a look at the assembly code, but couldn't see anything standing out that would explain such a drop in performance as I'm not an asm expert.
Edit 03-05-2018 :
Posted this bug : https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84719.
I find it suspicious that you get different code for memcpy vs __builtin_memcpy. I don't think that's supposed to happen, and indeed I cannot reproduce it on my (linux) system.
If you add #pragma GCC unroll 16 (implemented in gcc-8+) before the for loop, gcc gets the same perf as clang (making block a constant is essential to optimize the code), so essentially llvm's unrolling is more aggressive than gcc's, which can be good or bad depending on cases. Still, feel free to report it to gcc, maybe they'll tweak the unrolling heuristics some day and an extra testcase could help.
Once unrolling is taken care of, gcc does ok for some values (block equals 4 or 8 in particular), but much worse for some others, in particular 3. But that's better analyzed with a smaller testcase without the loop on block. Gcc seems to have trouble with memcpy(,,3), it works much better if you always read 8 bytes (the next line already takes care of the extra bytes IIUC). Another thing that could be reported to gcc.

Why gettimg error: undefined reference to `sqrt' when passing a variable, but it compiled successfully when passing constant as an argument [duplicate]

I created a small program, as follows:
#include <math.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int i;
double tmp;
double xx;
for(i = 1; i <= 30; i++) {
xx = (double) i + 0.01;
tmp = sqrt(xx);
printf("the square root of %0.4f is %0.4f\n", xx,tmp);
sleep(1);
xx = 0;
}
return 0;
}
When I try to compile this with the following command, I get a compiler error.
gcc -Wall calc.c -o calc
returns:
/tmp/ccavWTUB.o: In function `main':
calc.c:(.text+0x4f): undefined reference to `sqrt'
collect2: ld returned 1 exit status
If I replace the variable in the call to sqrt(xx) with a constant like sqrt(10.2), it compiles just fine. Or, if I explicitly link like the following:
gcc -Wall -lm calc.c -o calc
It also works just fine. Can anyone tell me what's causing this? I've been a C programmer for a long time (and I've written similar small programs using math.h) and I have never seen anything like this.
My version of gcc follows:
$ gcc --version
gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
If you look at the output of the compiler in the case where you used sqrt(10.2), I'll bet you see that a call to sqrt() isn't actually made.
This happens because GCC recognizes several functions that it can treat specially. This gives it the ability to do certain optimizations, in this case Constant folding. Such special functions are called Built-ins.
In the case where it must link to the math library (because you're calling it with a variable), you need to link it explicitly. Some operating systems/compilers do it for you, which is why you might not have noticed in the past.

Is GCC's -Wmaybe-uninitialized generating a spurious warning with -O1 for a switch statement based on an enum?

I have a piece of code of the following form:
typedef enum {A=1,B} EnumType;
int foo (EnumType x)
{
int r;
switch (x) {
case A:
r = 1;
break;
case B:
r = 2;
break;
/*
default:
r = -1;
break;
*/
}
return r;
}
I compile with GCC 6.3.0 and receive a warning:
$ gcc --version
gcc (MacPorts gcc6 6.3.0_2) 6.3.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gcc -c -Wall -O1 test.c
test.c: In function 'foo':
test.c:20:10: warning: 'r' may be used uninitialized in this function [-Wmaybe-uninitialized]
return r;
^
The code seems safe to me, and indeed there is some discussion of GCC producing false positives with this warning.
Is this a spurious warning?
More relevant information:
Adding the commented-out default: block resolves the warning
The warning does not appear with -O0
This warning is entirely correct, because an enum type doesn't restrict the possible values to the members defined in this enum -- it can instead hold any value of the underlying integer type. So without a default branch in your switch, you could indeed use r uninitialized with the code you show.
I can reproduce the warning missing with gcc and -O0 with the exact code shown in the question, so this looks to me like a bug in gcc. The warning should be given regardless of the optimization level.
It is easy to figure out: there are possible program paths where r will be returned uninitialised. So you got the warning. Enum is just the int so you have a lots possible cases.
Enums are not checked runtime against the values.
About the second part of the question. It is intentional as any level of optimisation may (and in this case will remove the code if the values of the enum type are illegal - compiler assumes that no other values are possible)
https://godbolt.org/g/S9XE3d
This case is most interesting:
https://godbolt.org/g/TDUhN7
You may think that you have checked against illegal values. But the compiler has stripped the code out :)
BTW - interesting why my answer was downvoted

sqrt from math.h causes linker error "undefined reference to sqrt" only when the argument is not a constant

I created a small program, as follows:
#include <math.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int i;
double tmp;
double xx;
for(i = 1; i <= 30; i++) {
xx = (double) i + 0.01;
tmp = sqrt(xx);
printf("the square root of %0.4f is %0.4f\n", xx,tmp);
sleep(1);
xx = 0;
}
return 0;
}
When I try to compile this with the following command, I get a compiler error.
gcc -Wall calc.c -o calc
returns:
/tmp/ccavWTUB.o: In function `main':
calc.c:(.text+0x4f): undefined reference to `sqrt'
collect2: ld returned 1 exit status
If I replace the variable in the call to sqrt(xx) with a constant like sqrt(10.2), it compiles just fine. Or, if I explicitly link like the following:
gcc -Wall -lm calc.c -o calc
It also works just fine. Can anyone tell me what's causing this? I've been a C programmer for a long time (and I've written similar small programs using math.h) and I have never seen anything like this.
My version of gcc follows:
$ gcc --version
gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
If you look at the output of the compiler in the case where you used sqrt(10.2), I'll bet you see that a call to sqrt() isn't actually made.
This happens because GCC recognizes several functions that it can treat specially. This gives it the ability to do certain optimizations, in this case Constant folding. Such special functions are called Built-ins.
In the case where it must link to the math library (because you're calling it with a variable), you need to link it explicitly. Some operating systems/compilers do it for you, which is why you might not have noticed in the past.

Resources