I have the following code:
const int a = 10;
int b = __builtin_constant_p(a);
printf("%d\n", b);
output is 0.
I read the man, the value of 0 doesn't mean that a is not a compile time constant, just that gcc can't prove that it is. Anyway I can get this output to be 1?
A const-qualified variable is not a constant expression in C, but GCC does not document __builtin_constant_p as determining if the argument is a constant expression anyway. Rather, it's documented to "determine if a value is known to be constant at compile time and hence that GCC can perform constant-folding on expressions involving that value". So it should be usable for what you want.
The problem is almost certainly just that you compiled with -O0 (no optimization, the default), in which case no constant-folding can take place because you have it turned off. Turn on optimization (at least -O1, but normally you want -O2 or -Os) and it should do what you want.
A variable is never a constant (unless constant folding is used, but you have to have optimization enabled for that), even if it is const-qualified.
__builtin_constant_p will return true for a constant only. For example:
int b = __builtin_constant_p(10);
printf("%d\n", b);
will print 1.
Note that your code will print 1 also if you compile with optimization enabled (-O at minimum, but any other legal -O flag will work except for -O0).
Related
OS: Ubuntu 18.04
GCC: 7.5.0
I'm writing an expression generator to test my simple debugger, and want to filter the expressions with division by zero behavior. However i encounter a troubling problem.
As for the definite division by zero behavior akin to int c = 1/0, it will raise a signal so i can handle these cases by signal(). Nevertheless, in the case akin to int c = 1/0*0, cis equal 0 , and the program will never trap into the signal handler.
The test code as below.
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
void ss(int sig){
printf("division by zero.\n");
exit(0);
}
int main(){
int c;
signal(SIGFPE, ss);
c = (1u/0u)*0u;
printf("%d\n", c);
}
Here is the result.
gcc -o divide_0 divide_0.c
divide_0.c: In function ‘main’:
divide_0.c:15:11: warning: division by zero [-Wdiv-by-zero]
c = (1u/0u)*0u;
^
0
How can i capture the warning in this case?
Forcing the compiler to execute a division by zero is actually hard:
First, as you have noted, the compiler may evaluate 1/0 at compile-time. To prevent it from knowing the divisor is zero, we can use a volatile object, as in volatile int zero = 0; c = 1/zero;. The volatile qualifier tells the compiler the object may be changed by means unknown to it, so it cannot assume it is zero and must get the value when the expression is being evaluated.
Multiplying by zero in (1u/0u)*0u is counterproductive, even after we change the divisor to zero. The compiler can reason that any defined result of (1u/zero)*0u is zero, and therefore it is allowed to use zero as the union of the defined results (zero) and the undefined results (whatever the compiler likes), so it can replace (1u/zero)*0u with zero, 0. That is, it must still evaluate zero because it is volatile, but then it is free to just produce zero as the result without doing the division.
The compiler does not have to use a division instruction to evaluate a division operator. I tested with Apple Clang 11, and it was evaluating 1u/zero with instructions equivalent to zero == 1 ? 1 : 0;. In other words, it just did a compare and a set, not a division, presumably because compare and set is faster. When I changed this to 13u/zero, then the compiler used a divide instruction. I expect your best bet for getting a divide instruction would be to use volatile int unknown = 0; unknown = unknown/unknown;. Even then, a compiler would be allowed by the C standard to perform the division using any instructions it wanted, not a divide. But I presume compilers will generally generate a divide instruction in this case.
Then this code will execute a division at run-time. Whether that causes a signal and what happens with that signal depends on your computing platform.
Division by zero is not guaranteed to generate a signal.
Whenever your expression evaluator performs a division, it needs to check if the divisor is 0, and if so perform an appropriate action.
I assume that the compiler somehow just removes the division. It is allowed to do that. So instead try this code:
int main(int argc, char **argv){
int c;
int d = argc - 1;
signal(SIGFPE, ss);
c = 1u/d;
printf("%d\n", c);
}
Call it without arguments. The trick here is that the compiler cannot know how many arguments you will give the program, so it cannot optimize it away. Well, not as easily anyway.
The compiler itself complains about this since it can tell that your code is faulty and unsafe. However, you can try to use -Wno-div-by-zero argument for gcc at your own risk.
Is there a way in C to programmatically determine that variable's value was computed at compile time or at run time?
Example:
const double a = 2.0;
const double b = 3.0;
double c1 = a / b; // done at compile time (constant folding / propagation)
double c2 = *(volatile double*)&a / *(volatile double*)&b; // done at run time
compute_time_t c1_ct = compute_time(c1);
compute_time_t c2_ct = compute_time(c2);
assert(c1_ct == COMPILE_TIME);
assert(c2_ct == RUN_TIME);
In C (as in, defined by the language standard), no, there is no way.
There are however compiler-specific ways using which you can get really close to achieving what you want. The most famous, as #Nate Eldredge notes in the comments, is the builtin function __builtin_constant_p() available in GCC and Clang.
Here's the relevant excerpt from the GCC doc:
Built-in Function: int __builtin_constant_p (exp)
You can use the built-in function __builtin_constant_p to determine if a value is known to be constant at compile time and hence that GCC can perform constant-folding on expressions involving that value. The argument of the function is the value to test. The function returns the integer 1 if the argument is known to be a compile-time constant and 0 if it is not known to be a compile-time constant. A return of 0 does not indicate that the value is not a constant, but merely that GCC cannot prove it is a constant with the specified value of the -O option.
Note that this function does not guarantee to detect all compile-time constants, but only the ones that GCC is able to prove as such. Different optimization levels might change the result returned by this function.
This built-in function is widely used in glibc for optimization purposes (example), and usually the result is only trusted when it's 1, assuming a non-constant otherwise:
void somefunc(int x) {
if (__builtin_constant_p(x)) {
// Perform optimized operation knowing x is a compile-time constant.
} else {
// Assume x is not a compile-time constant.
}
}
Using your own example:
const double a = 2.0;
const double b = 3.0;
double c1 = a / b; // done at compile time (constant folding / propagation)
double c2 = *(volatile double*)&a / *(volatile double*)&b; // done at run time
assert(__builtin_constant_p(c1));
assert(!__builtin_constant_p(c2));
You ask,
Is there a way in C to programmatically determine that variable's
value was computed at compile time or at run time?
No, there is no way to encode such a determination into the source of a strictly conforming C program.
Certainly C does not require values to be tagged systematically in a way that distinguishes among them based on when they were computed, and no C implementation I have ever heard of or imagined does that, so such a determination cannot be based on the values of the expressions of interest. Furthermore, all C function arguments are passed by value, so the hypothetical compute_time() cannot be implemented as a function because values are all it would have to work with.
compute_time() also cannot be a macro, because macros can work only with (preprocessing) tokens, for example the identifiers c1 and c2 in your example code. Those are opaque to the preprocessor; it knows nothing about values attributed to them when they are evaluated as expressions according to C semantics.
And there is no operator that serves the purpose.
Standard C provides no other alternatives, so if the question is about the C language and not any particular implementation of it then that's the end of the story. Moreover, although it is conceivable that a given C implementation would provide your compute_time() or a functional equivalent as an extension, I am unaware of any that do. (However, see #MarcoBonelli's answer, for an example of a similar, but not identical, extension.)
Mathematically, 0 / 0 is undefined. But, in C programming (especially gcc compiler gcc-7.3.0 on ubuntu), it produces the answer as 1. I would like to know the reason. Is it working by repeated subtraction? For, the same code, if I use n = 1 / n, I get a floating point exception. However, for gcc-5.3.0, it produces an error.
#include <stdio.h>
int main() {
int n = 5;
n = n - 5;
switch (n) {
case 0:
printf("n= %d", n);
n = n / n;
printf("n calc= %d", n);
break;
case 5:
printf("n=5");
break;
default:
printf("n=1");
break;
}
return 0;
}
Divide by zero is undefined behavior in C programming (C11 6.5.5 §6). Meaning that there is no predictable result, there is no telling what your program might do.
It isn't very meaningful to try reason about why you get one particular outcome of "anything might happen". It might print 1, it might print 42, it might print nothing at all. The program might crash and burn. If you run the program twice, you might get different outcomes. And so on.
As for why you won't get a compiler error, the compiler isn't able or obliged to find or diagnose run-time errors. Most cases of undefined behavior need to be avoided by the programmer.
Some good compilers may be able to give warnings if you use pure integer constant expressions such as int x = 0/0;, but again it is not the job of the compiler to find this bug. It is the programmer's job. Therefore you should make a habit of always checking if the right operand of / or % is zero before applying the operands.
Compilers are allowed to assume that the code does not invoke undefined behavior, and use that assumption while optimizing the code.
For any value, other than n==0 the expression n/n evaluates as 1. Since diving by zero is undefined behavior in C, the compiler can assume that this scenario never happens, i.e., it can assume that n!=0.
Since it may assume that, the compiler can replace the slow n/n with the cheap constant value of 1. This is probably what happens with the code in question.
Of course, the compiler is not required to make any such assumption, and might generate an actual division. Depending on the hardware that executes the code, a specific hardware signal (or exception) might be triggered in such a case of division by zero. I doubt that any reasonable compiler will emit division in this example for optimized code, because division is extremely slow, and according to the standard the constant 1 is good enough. However, it is still likely it will produce an actual division in debug mode.
Similar things happen when optimizing away other undefined behavior, such as int overflow:
void f(int x)
{
if (x > x + 1)
// executed only in case of overflow,
// which is undefined behavior,
// and hence likely optimized out.
overflow_error();
...
Don't rely on undefined behavior - it is not predictable.
As can be seen on Godbolt's compiler explorer, both gcc and clang optimize n / n for n integer to evaluate to 1 without any warning. gcc performs this optimisation even at -O0 whereas clang generates the division opcode for -O0 but the optimized alternative for -O1 and above.
0 / 0 has undefined behavior anyway, therefore any behavior for n / n is OK if n is zero, including evaluating to 1 without an observable side-effect.
If you insist, you could qualify n as volatile and the compiler might generate a division, as both gcc and clang do in this case, but as long as n is read twice, it does not have to.
What happens in C when you create an array of negative length?
For instance:
int n = -35;
int testArray[n];
for(int i = 0; i < 10; i++)
testArray[i]=i+1;
This code will compile (and brings up no warnings with -Wall enabled), and it seems you can assign to testArray[0] without issue. Assigning past that gives either a segfault or illegal instruction error, and reading anything from the array says "Abort trap" (I'm not familiar with that one). I realize this is somewhat academic, and would (hopefully) never come up in real life, but is there any particular way that the C standard says to treat such arrays, or is does it vary from compiler to compiler?
It's undefined behaviour, because it breaks a "shall" constraint:
C99 §6.7.5.2:
If the size is an expression that is
not an integer constant expression...
...each time it is evaluated it shall
have a value greater than zero.
Undefined behavior, I believe, though don't quote me on that.
This gives the error error: size of array 'testArray' is negative in gcc:
int testArray[-35];
though, as you've seen:
int n = -35;
int testArray[n];
does not give an error even with both -Wall and -W.
However, if you use -pedantic flag, gcc will warn that ISO C90 forbids variable length array.
Visual studio erro message for compilation, you can use -1 to say an empty array. It expects int and you are passing int, so no compiler error.
I have been advised to use the following options with GCC, as it helps to avoid a lot of common errors. It turns on a bunch of warnings and -Werror turns them into errors.
gcc -pedantic -W -Wall -Wextra -Wshadow -Wstrict-overflow=5 -Wwrite-strings -std=c99 -Werror
Given the following test code:
#include <stdio.h>
int main(void)
{
int arr[8]={0,10,20,30,40,50,60,70};
int x;
printf("sizeof(arr): %d\n", sizeof(arr));
printf("sizeof(int): %d\n", sizeof(int));
for(x = 0; x < sizeof(arr)/sizeof(int); x++)
{
printf("%d\n",arr[x]);
}
return 0;
}
I get this:
test.c:11: error: comparison between signed and unsigned
I know that one way I can fix this is turning off the warnings, but they haven't made me use these settings to turn them off in the end.
Another way is to cast the stuff, but I have been told that casting is deprecated.
Also, I could make x into an unsigned int:
unsigned x;
But it doesn't solve the general problem when I have to compare signed values with unsigned values using these compiler options. Is there an cleaner way instead of casting?
Replace
int x;
/* ... */
for(x=0;x<sizeof(arr) / sizeof(int);x++)
by
for(size_t x=0;x<sizeof(arr) / sizeof(int);x++)
But it doesn't solve the general problem when I have to compare signed values with unsigned values using these compiler options. Is there an cleaner way insted of casting?
In such cases, try to figure out if the signed number can ever have a value which will cause overflow. If not, you can ignore the warning. Otherwise a cast to the unsigned type (if this is the same size or bigger than the signed component) is good enough.
This really depends on the data type. It is possible to avoid this by implicitly casting the values to a type which contains a superset of all the values available in the signed and unsigned type. For instance you could use a 64 bit signed value to compare an unsigned 32 bit and a signed 32 bit value.
However this is a corner case and you need to do operations like verify the size of your types. Your best solution is to use the same type for both operands.
If you must cast, do consider that you could be causing an overflow and consider if that is important to your application or not.
The crux of the matter is that comparing signed and unsigned values admits some weird cases. Consider, for instance, what happens in the unsigned array length is larger than the maximum that can be represented by a signed int. The signed counter overflow (remaining "less than" the array size), and you start addressing memory you didn't mean to...
The compiler generates a warning to make sure that you're thinking about them. Using -Werror promotes that warning to an error and stops the compilation.
Either be rigorous about choosing the signedeness of your types, or cast the trouble away when you're sure it doesn't apply, or get rid of -Werror and make it a policy to address all warnings with a fix or an explanation...
One workaround would be to selectively disable that one warning in this special case.
GCC has pragma diagnostic ignored "-Wsomething"
// Disable a warning for a block of code:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
// ... Some code where the specified warning should be suppressed ...
#pragma GCC diagnostic pop
Recent versions of GCC (I am not actually sure since when, but 4.8.x should support it) show the corresponding -Wsomething option. This is important since most warning options are not set explicitly but en bloc with options like -Wall.
An error message would look like this:
readers.c: In function ‘buffered_fullread’:
readers.c:864:11: error: comparison between signed and unsigned integer expressions [-Werror=sign-compare]
if(got < sizeof(readbuf)) /* That naturally catches got == 0, too. */
The [-Werror=sign-compare] part tells You You can use "Wsign-compare" for "Wsomething" to suppress the warning.
And of course, You should only do that where it is appropriate (it does not quite help readability), e.g. when exactly the behaviour that the compiler warns about is wanted (or, if You may not introduce bigger changes in the code base).
test.c:11: error: comparison between signed and unsigned
You could declare x as an unsigned int, since size_t is unsigned
EDIT:
If you don't want to cast, and don't want to declare it as unsigned, i don't think there's much to do.
Maybe bitwise operations are a way of solving it, removing the sign bit. I have to say, IMO its very questionable though.
We suppress this warning in our Visual Studio compiles, since it happens a lot and almost never means anything significant. Of course, not all coding standards allow that.
You can make types agree (declaring variables to be size_t or unsigned int instead of int, for example), or you can cast, or you can change your compilation line. That's about it.
Regardless of the casting deprecation dilemma, I'd still suggest separating out the logic from the for loop.
int range = (int)(sizeof(arr) / sizeof(int));
int x;
for(x = 0; x < range; x++)
{
printf("%d\n", arr[x]);
}
Although this uses casting which you said was deprecated, it clears up the location where the casting is taking place. In general, I advise against cramming a lot of logic into your for loop declarations. Especially in your case where you're using size_t division, which (because it is integer division) could have the possibility of truncating the answer. The for loop declaration should be clean, and should generate no errors. Your casting is occuring in a different location which means if you want to change the way you are creating the range, you don't have to muck about making the for declaration even longer.