At first glance, this question may seem like a duplicate of How to detect integer overflow?, however it is actually significantly different.
I've found that while detecting an unsigned integer overflow is pretty trivial, detecting a signed overflow in C/C++ is actually more difficult than most people think.
The most obvious, yet naive, way to do it would be something like:
int add(int lhs, int rhs)
{
int sum = lhs + rhs;
if ((lhs >= 0 && sum < rhs) || (lhs < 0 && sum > rhs)) {
/* an overflow has occurred */
abort();
}
return sum;
}
The problem with this is that according to the C standard, signed integer overflow is undefined behavior. In other words, according to the standard, as soon as you even cause a signed overflow, your program is just as invalid as if you dereferenced a null pointer. So you can't cause undefined behavior, and then try to detect the overflow after the fact, as in the above post-condition check example.
Even though the above check is likely to work on many compilers, you can't count on it. In fact, because the C standard says signed integer overflow is undefined, some compilers (like GCC) will optimize away the above check when optimization flags are set, because the compiler assumes a signed overflow is impossible. This totally breaks the attempt to check for overflow.
So, another possible way to check for overflow would be:
int add(int lhs, int rhs)
{
if (lhs >= 0 && rhs >= 0) {
if (INT_MAX - lhs <= rhs) {
/* overflow has occurred */
abort();
}
}
else if (lhs < 0 && rhs < 0) {
if (lhs <= INT_MIN - rhs) {
/* overflow has occurred */
abort();
}
}
return lhs + rhs;
}
This seems more promising, since we don't actually add the two integers together until we make sure in advance that performing such an add will not result in overflow. Thus, we don't cause any undefined behavior.
However, this solution is unfortunately a lot less efficient than the initial solution, since you have to perform a subtract operation just to test if your addition operation will work. And even if you don't care about this (small) performance hit, I'm still not entirely convinced this solution is adequate. The expression lhs <= INT_MIN - rhs seems exactly like the sort of expression the compiler might optimize away, thinking that signed overflow is impossible.
So is there a better solution here? Something that is guaranteed to 1) not cause undefined behavior, and 2) not provide the compiler with an opportunity to optimize away overflow checks? I was thinking there might be some way to do it by casting both operands to unsigned, and performing checks by rolling your own two's-complement arithmetic, but I'm not really sure how to do that.
No, your 2nd code isn't correct, but you are close: if you set
int half = INT_MAX/2;
int half1 = half + 1;
the result of an addition is INT_MAX. (INT_MAX is always an odd number). So this is valid input. But in your routine you will have INT_MAX - half == half1 and you would abort. A false positive.
This error can be repaired by putting < instead of <= in both checks.
But then also your code isn't optimal. The following would do:
int add(int lhs, int rhs)
{
if (lhs >= 0) {
if (INT_MAX - lhs < rhs) {
/* would overflow */
abort();
}
}
else {
if (rhs < INT_MIN - lhs) {
/* would overflow */
abort();
}
}
return lhs + rhs;
}
To see that this is valid, you have to symbolically add lhs on both sides of the inequalities, and this gives you exactly the arithmetical conditions that your result is out of bounds.
Your approach with subtraction is correct and well-defined. A compiler cannot optimize it away.
Another correct approach, if you have a larger integer type available, is to perform the arithmetic in the larger type and then check that the result fits in the smaller type when converting it back
int sum(int a, int b)
{
long long c;
assert(LLONG_MAX>INT_MAX);
c = (long long)a + b;
if (c < INT_MIN || c > INT_MAX) abort();
return c;
}
A good compiler should convert the entire addition and if statement into an int-sized addition and a single conditional jump-on-overflow and never actually perform the larger addition.
Edit: As Stephen pointed out, I'm having trouble getting a (not-so-good) compiler, gcc, to generate the sane asm. The code it generates is not terribly slow, but certainly suboptimal. If anyone knows variants on this code that will get gcc to do the right thing, I'd love to see them.
For the gcc case, from gcc 5.0 Release notes we can see it now provides a __builtin_add_overflow for checking overflow in addition:
A new set of built-in functions for arithmetics with overflow checking has been added: __builtin_add_overflow, __builtin_sub_overflow and __builtin_mul_overflow and for compatibility with clang also other variants. These builtins have two integral arguments (which don't need to have the same type), the arguments are extended to infinite precision signed type, +, - or * is performed on those, and the result is stored in an integer variable pointed to by the last argument. If the stored value is equal to the infinite precision result, the built-in functions return false, otherwise true. The type of the integer variable that will hold the result can be different from the types of the first two arguments.
For example:
__builtin_add_overflow( rhs, lhs, &result )
We can see from the gcc document Built-in Functions to Perform Arithmetic with Overflow Checking that:
[...]these built-in functions have fully defined behavior for all argument values.
clang also provides a set of checked arithmetic builtins:
Clang provides a set of builtins that implement checked arithmetic for security critical applications in a manner that is fast and easily expressable in C.
in this case the builtin would be:
__builtin_sadd_overflow( rhs, lhs, &result )
The fastest possible way is to use the GCC builtin:
int add(int lhs, int rhs) {
int sum;
if (__builtin_add_overflow(lhs, rhs, &sum))
abort();
return sum;
}
On x86, GCC compiles this into:
mov %edi, %eax
add %esi, %eax
jo call_abort
ret
call_abort:
call abort
which uses the processor's built-in overflow detection.
If you're not OK with using GCC builtins, the next fastest way is to use bit operations on the sign bits. Signed overflow in addition occurs when:
the two operands have the same sign, and
the result has a different sign than the operands.
The sign bit of ~(lhs ^ rhs) is on iff the operands have the same sign, and the sign bit of lhs ^ sum is on iff the result has a different sign than the operands. So you can do the addition in unsigned form to avoid undefined behavior, and then use the sign bit of ~(lhs ^ rhs) & (lhs ^ sum):
int add(int lhs, int rhs) {
unsigned sum = (unsigned) lhs + (unsigned) rhs;
if ((~(lhs ^ rhs) & (lhs ^ sum)) & 0x80000000)
abort();
return (int) sum;
}
This compiles into:
lea (%rsi,%rdi), %eax
xor %edi, %esi
not %esi
xor %eax, %edi
test %edi, %esi
js call_abort
ret
call_abort:
call abort
which is quite a lot faster than casting to a 64-bit type on a 32-bit machine (with gcc):
push %ebx
mov 12(%esp), %ecx
mov 8(%esp), %eax
mov %ecx, %ebx
sar $31, %ebx
clt
add %ecx, %eax
adc %ebx, %edx
mov %eax, %ecx
add $-2147483648, %ecx
mov %edx, %ebx
adc $0, %ebx
cmp $0, %ebx
ja call_abort
pop %ebx
ret
call_abort:
call abort
IMHO, the eastiest way to deal with overflow sentsitive C++ code is to use SafeInt<T>. This is a cross platform C++ template hosted on code plex which provides the safety guarantees that you desire here.
https://github.com/dcleblanc/SafeInt
I find it very intuitive to use as it provides the many of the same usage patterns as normal numerical opertations and expresses over and under flows via exceptions.
If you use inline assembler you can check the overflow flag. Another possibility is taht you can use a safeint datatype. I recommend that read this paper on Integer Security.
The obvious solution is to convert to unsigned, to get the well-defined unsigned overflow behavior:
int add(int lhs, int rhs)
{
int sum = (unsigned)lhs + (unsigned)rhs;
if ((lhs >= 0 && sum < rhs) || (lhs < 0 && sum > rhs)) {
/* an overflow has occurred */
abort();
}
return sum;
}
This replaces the undefined signed overflow behavior with the implementation-defined conversion of out-of-range values between signed and unsigned, so you need to check your compiler's documentation to know exactly what will happen, but it should at least be well defined, and should do the right thing on any twos-complement machine that doesn't raise signals on conversions, which is pretty much every machine and C compiler built in the last 20 years.
Your fundamental problem is that lhs + rhs doesn't do the right thing. But if you're willing to assume a two's complement machine, we can fix that. Suppose you have a function to_int_modular that converts unsigned to int in a way that is guaranteed to be the inverse of conversion from int to unsigned, and it optimizes away to nothing at run time. (See below for how to implement it.)
If you use it to fix the undefined behavior in your original attempt, and also rewrite the conditional to avoid the redundant test of lhs >= 0 and lhs < 0, then you get
int add(int lhs, int rhs)
{
int sum = to_int_modular((unsigned)lhs + rhs);
if (lhs >= 0) {
if (sum < rhs)
abort();
} else {
if (sum > rhs)
abort();
}
return sum;
}
which should outperform the current top-voted answer, since it has a similar structure but requires fewer arithmetic operations.
(Reorganizing the if shouldn't be necessary, but in tests on godbolt, ICC and MSVC do eliminate the redundant test on their own, but GCC and Clang surprisingly don't.)
If you prefer to compute the result in a wider size and then bounds check, one way to do the bounds check is
long long sum = (long long)lhs + rhs;
if ((int)sum != sum)
abort();
... except that the behavior is undefined on overflow. But you can fix that with the same helper function:
if (to_int_modular(sum) != sum)
This will probably outperform the current accepted answer on compilers that aren't smart enough to optimize it to a test of the overflow flag.
Unfortunately, testing (visual inspection on godbolt) suggests that GCC, ICC and MSVC do better with the code above than with the code in the accepted answer, but Clang does better with the code in the accepted answer. As usual, nothing is easy.
This approach can only work on architectures where the ranges of int and unsigned are equally large, and the specific implementations below also depend on its being two's complement. Machines not meeting those specs are vanishingly rare, but I'll check for them anyway:
static_assert(INT_MIN + INT_MAX == -1 && UINT_MAX + INT_MIN == INT_MAX);
One way to implement to_int_modular is
inline int to_int_modular(unsigned u) {
int i;
memcpy(&i, &u, sizeof(i));
return i;
}
All major x64 compilers have no trouble optimizing that to nothing, but when optimizations are disabled, MSVC and ICC generate a call to memcpy, which may be a bit slow if you use this function a lot. This implementation also depends on details of the representation of unsigned and int that probably aren't guaranteed by the standard.
Another way is this:
inline int to_int_modular(unsigned u) {
return u <= INT_MAX ? (int)u : (int)(u - INT_MIN) + INT_MIN;
}
All major x64 compilers optimize that to nothing except ICC, which makes an utter mess of it and every variation that I could think of. ICX does fine, and it appears that Intel is abandoning ICC and moving to ICX, so maybe this problem will fix itself.
You may have better luck converting to 64-bit integers and testing similar conditions like that. For example:
#include <stdint.h>
...
int64_t sum = (int64_t)lhs + (int64_t)rhs;
if (sum < INT_MIN || sum > INT_MAX) {
// Overflow occurred!
}
else {
return sum;
}
You may want to take a closer look at how sign extension will work here, but I think it is correct.
How about:
int sum(int n1, int n2)
{
int result;
if (n1 >= 0)
{
result = (n1 - INT_MAX)+n2; /* Can't overflow */
if (result > 0) return INT_MAX; else return (result + INT_MAX);
}
else
{
result = (n1 - INT_MIN)+n2; /* Can't overflow */
if (0 > result) return INT_MIN; else return (result + INT_MIN);
}
}
I think that should work for any legitimate INT_MIN and INT_MAX (symmetrical or not); the function as shown clips, but it should be obvious how to get other behaviors).
In case of adding two long values, portable code can split the long value into low and high int parts (or into short parts in case long has the same size as int):
static_assert(sizeof(long) == 2*sizeof(int), "");
long a, b;
int ai[2] = {int(a), int(a >> (8*sizeof(int)))};
int bi[2] = {int(b), int(b >> (8*sizeof(int))});
... use the 'long' type to add the elements of 'ai' and 'bi'
Using inline assembly is the fastest way if targeting a particular CPU:
long a, b;
bool overflow;
#ifdef __amd64__
asm (
"addq %2, %0; seto %1"
: "+r" (a), "=ro" (overflow)
: "ro" (b)
);
#else
#error "unsupported CPU"
#endif
if(overflow) ...
// The result is stored in variable 'a'
By me, the simpliest check would be checking the signs of the operands and of the results.
Let's examine sum: the overflow could occur in both directions, + or -, only when both operands have the same sign. And, obviosly, the overflow will be when the sign of the result won't be the same as the sign of the operands.
So, a check like this will be enough:
int a, b, sum;
sum = a + b;
if (((a ^ ~b) & (a ^ sum)) & 0x80000000)
detect_oveflow();
Edit: as Nils suggested, this is the correct if condition:
((((unsigned int)a ^ ~(unsigned int)b) & ((unsigned int)a ^ (unsigned int)sum)) & 0x80000000)
And since when the instruction
add eax, ebx
leads to undefined behavior? There is no such thing in the Intel x86 instruction set refference..
I think that this works:
int add(int lhs, int rhs) {
volatile int sum = lhs + rhs;
if (lhs != (sum - rhs) ) {
/* overflow */
//errno = ERANGE;
abort();
}
return sum;
}
Using volatile keeps the compiler from optimizing away the test because it thinks that sum may have changed between the addition and the subtraction.
Using gcc 4.4.3 for x86_64 the assembly for this code does do the addition, the subtraction, and the test, though it stores everything on the stack and of unneeded stack operations. I even tried register volatile int sum = but the assembly was the same.
For a version with only int sum = (no volatile or register) the function did not do the test and did the addition using only one lea instruction (lea is Load Effective Address and is often used to do addition without touching the flags register).
Your version is larger code and has a lot more jumps, but I don't know which would be better.
This is a complete rewrite of the question. Hopefully it is clearer now.
I want to implement in C a function that performs addition of signed ints with wrapping in case of overflow.
I want to target mainly the x86-64 architecture, but of course the more portable the implementation is the better. I'm also concerned mostly about producing decent assembly code through gcc, clang, icc, and whatever is used on Windows.
The goal is twofold:
write correct C code that doesn't fall into the undefined behavior blackhole;
write code that gets compiled to decent machine code.
By decent machine code I mean a single leal or a single addl instruction on machines which natively support the operation.
I'm able to satisfy either of the two requisites, but not both.
Attempt 1
The first implementation that comes to mind is
int add_wrap(int x, int y) {
return (unsigned) x + (unsigned) y;
}
This seems to work with gcc, clang and icc. However, as far as I know, the C standard doesn't specify the cast from unsigned int to signed int, leaving freedom to the implementations (see also here).
Otherwise, if the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
I believe most (all?) major compilers do the expected conversion from unsigned to int, meaning that they take the correct representative modulus 2^N, where N is the number of bits, but it's not mandated by the standard so it cannot be relied upon (stupid C standard hits again). Also, while this is the simplest thing to do on two's complement machines, it is impossible on ones' complement machines, because there is a class which is not representable: 2^(N/2).
Attempt 2
According to the clang docs, one can use __builtin_add_overflow like this
int add_wrap(int x, int y) {
int res;
__builtin_add_overflow(x, y, &res);
return res;
}
and this should do the trick with clang, because the docs clearly say
If possible, the result will be equal to mathematically-correct result and the builtin will return 0. Otherwise, the builtin will return 1 and the result will be equal to the unique value that is equivalent to the mathematically-correct result modulo two raised to the k power, where k is the number of bits in the result type.
The problem is that in the GCC docs they say
These built-in functions promote the first two operands into infinite precision signed type and perform addition on those promoted operands. The result is then cast to the type the third pointer argument points to and stored there.
As far as I know, casting from long int to int is implementation specific, so I don't see any guarantee that this will result in the wrapping behavior.
As you can see [here][godbolt], GCC will also generate the expected code, but I wanted to be sure that this is not by chance ans is indeed part of the specification of __builtin_add_overflow.
icc also seems to produce something reasonable.
This produces decent assembly, but relies on intrinsics, so it's not really standard compliant C.
Attempt 3
Follow the suggestions of those pedantic guys from SEI CERT C Coding Standard.
In their CERT INT32-C recommendation they explain how to check in advance for potential overflow. Here is what comes out following their advice:
#include <limits.h>
int add_wrap(int x, int y) {
if ((x > 0) && (y > INT_MAX - x))
return (x + INT_MIN) + (y + INT_MIN);
else if ((x < 0) && (y < INT_MIN - x))
return (x - INT_MIN) + (y - INT_MIN);
else
return x + y;
}
The code performs the correct checks and compiles to leal with gcc, but not with clang or icc.
The whole CERT INT32-C recommendation is complete garbage, because it tries to transform C into a "safe" language by forcing the programmers to perform checks that should be part of the definition of the language in the first place. And in doing so it forces also the programmer to write code which the compiler can no longer optimize, so what is the reason to use C anymore?!
Edit
The contrast is between compatibility and decency of the assembly generated.
For instance, with both gcc and clang the two following functions which are supposed to do the same get compiled to different assembly.
f is bad in both cases, g is good in both cases (addl+jo or addl+cmovnol). I don't know if jo is better than cmovnol, but the function g is consistently better than f.
#include <limits.h>
signed int f(signed int si_a, signed int si_b) {
signed int sum;
if (((si_b > 0) && (si_a > (INT_MAX - si_b))) ||
((si_b < 0) && (si_a < (INT_MIN - si_b)))) {
return 0;
} else {
return si_a + si_b;
}
}
signed int g(signed int si_a, signed int si_b) {
signed int sum;
if (__builtin_add_overflow(si_a, si_b, &sum)) {
return 0;
} else {
return sum;
}
}
A bit like #Andrew's answer without the memcpy().
Use a union to negate the need for memcpy(). With C2x, we are sure that int is 2's compliment.
int add_wrap(int x, int y) {
union {
unsigned un;
int in;
} u = {.un = (unsigned) x + (unsigned) y};
return u.in;
}
For those who like 1-liners, use a compound literal.
int add_wrap2(int x, int y) {
return ( union { unsigned un; int in; }) {.un = (unsigned) x + (unsigned) y}.in;
}
I'm not so sure because of the rules for casting from unsigned to signed
You exactly quoted the rules. If you convert from a unsigned value to a signed one, then the result is implementation-defined or a signal is raised. In simple words, what will happen is described by your compiler.
For example the gcc9.2.0 compiler has the following to in it's documentation about implementation defined behavior of integers:
The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 and C11 6.3.1.3).
For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.
I had to do something similar; however, I was working with known width types from stdint.h and needed to handle wrapping 32-bit signed integer operations. The implementation below works because stdint types are required to be 2's complement. I was trying to emulate the behaviour in Java, so I had some Java code generate a bunch of test cases and have tested on clang, gcc and MSVC.
inline int32_t add_wrap_i32(int32_t a, int32_t b)
{
const int64_t a_widened = a;
const int64_t b_widened = b;
const int64_t sum = a_widened + b_widened;
return (int32_t)(sum & INT64_C(0xFFFFFFFF));
}
inline int32_t sub_wrap_i32(int32_t a, int32_t b)
{
const int64_t a_widened = a;
const int64_t b_widened = b;
const int64_t difference = a_widened - b_widened;
return (int32_t)(difference & INT64_C(0xFFFFFFFF));
}
inline int32_t mul_wrap_i32(int32_t a, int32_t b)
{
const int64_t a_widened = a;
const int64_t b_widened = b;
const int64_t product = a_widened * b_widened;
return (int32_t)(product & INT64_C(0xFFFFFFFF));
}
It seems ridiculous, but I think that the recommended method is to use memcpy. Apparently all modern compilers optimize the memcpy away and it ends up doing just what you're hoping in the first place -- preserving the bit pattern from the unsigned addition.
int a;
int b;
unsigned u = (unsigned)a + b;
int result;
memcpy(&result, &u, sizeof(result));
On x86 clang with optimization, this is a single instruction if the destination is a register.
I want to iterate over all possible values of signed int, from INT_MIN to INT_MAX. The obvious code
for (int x = INT_MIN; x <= INT_MAX; x++)
do_something(x);
is broken due to undefined behavior caused by signed integer overflow. What is worth noting is that so is its apparently clever variant
int x = INT_MIN;
do {
do_something(x);
} while (x++ < INT_MAX);
What is interesting is that in this second example clang -O2 -fsanitize=undefined correctly reports the runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int', while gcc -O2 -fsanitize=undefined does not. I imagine gcc's -fsanitize=signed-integer-overflow is as broken as -ftrapv.
The only ways I could find to express this iteration are with a goto:
int x = INT_MIN;
loop: {
do_something(x);
if (x < INT_MAX) {
x++;
goto loop;
}
}
using an infinite loop and breaking manually:
int x = INT_MIN;
while (1) {
do_something(x);
if (x < INT_MAX)
x++;
else
break;
}
and exploiting the short-circuit evaluation to increment the variable only when it's safe to do so:
int x = INT_MIN;
do {
do_something(x);
} while (x < INT_MAX && ++x != INT_MIN);
As pointed out by Steve Jessop, in the do-while solution one can use while (x < INT_MAX && (++x, 1)); instead.
Among the three version, I'm not particularly against the goto version, I don't like the do-while version very much (especially the ++x != INT_MIN bit...), but all in all I prefer the while (1) version. My question is the following.
Is a C compiler allowed to completely eliminate the infinite while (1) loop in case do_something doesn't perform input/output operations, nor accesses volatile objects?
I know that it cannot for C11, but I'm not so sure about previous versions.
Edit
I will try to describe more in detail what I'm worried about. Let's say that I'm using this loop to validate the correctness of some other code. For instance, I might do
#include <stdio.h>
#include <limits.h>
int add_wrap_unsigned(int x, int y) {
return (unsigned) x + (unsigned) y;
}
int add_wrap_builtin(int x, int y) {
int res;
__builtin_add_overflow(x, y, &res);
return res;
}
int check() {
int x = INT_MIN;
while (1) {
if (add_wrap_unsigned(x, 1) != add_wrap_builtin(x, 1))
return 1;
if (x < INT_MAX)
x++;
else
break;
}
return 0;
}
int main() {
if (check())
printf("counterexample found");
else
printf("no counterexample");
return 0;
}
This correctly reports no counterexample with clang. check gets compiled to a simple return 0. However, changing a single line (line 22 from break; to x = INT_MIN;) changes completely the behavior: check becomes a noop infinite loop, but main now prints counterexample found. All this happens even with -std=c11.
My worry is that I cannot trust the first version, because the compiler might not have done the correct thing, as in the second case.
The question is whether the C compiler is allowed to remove an infinite loop. No, it is not allowed to remove an infinite loop whose controlling expression is constant (for (;;) {} or while (1) { }), but the C standard explicitly states in C11/C17 6.8.5p6 that
An iteration statement whose controlling expression is not a constant expression,156) that performs no input/output operations, does not access volatile objects, and performs no synchronization or atomic operations in its body, controlling expression, or (in the case of a for statement) its expression-3, may be assumed by the implementation to terminate.157)
I.e. the compiler is allowed to optimize out a loop that does not have any side effects and that does have a non-constant controlling expression. I.e. it is an utterly useless loop when it comes to the as-if rule. This exception has been granted in the C11 revision of the standard. This did not apply before C11 so if that behaviour was present then then it wasn't standards-compliant.
You do not need to guard the increment, just break:
for (int x = INT_MIN; ; x++) {
do_something(x);
if (x == INT_MAX) break;
}
In this case, the controlling expression is a constant expression (implicit true value), and hence must not be optimized out as per C11/C17 6.8.5p6, but the compiler must prove it explicitly to terminate.
Now what this gets optimized to depends on the compiler and the flags - with -O3 Clang 9.0 compiles it to the equivalent of
for (int x = INT_MIN; x != INT_MIN; x++)
do_something(x)
if the overflow were defined with wraparound - but as we know, x86 machine code does have well-defined wraparound.
The behaviour of the machine code produced by GCC 9.2 is similar to
int x = INT_MIN;
do_something(x);
do {
do_something(++x);
} while (x < INT_MAX);
which written like that in C would be free of undefined behaviour and virtually indistinguishable in performance from that of by Clang (but not in size).
I am learning bit algorithm and saw the equation that finds the max of two values:
r = x ^ ((x ^ y) & -(x < y)); // max(x, y)
The explanation says this equation will find the max without using comparison and "if x < y, then -(x < y) will be all ones". I cannot comprehend what the explanation means because I see a "less than" operator in the equation and if that is an less than operator, (x < y) should return only one bit of data. Therefore, for the explanation to make sense, the sign "<" cannot be the less than operator. I looked at the list of C operators and did not find other meanings for operator "<". Can someone tell me what does the operator "<" do in this equation? Thanks!
This is a very tricky code. The truth is that C does not have any Boolean type: it uses integer instead: 0 for false and 1 for true.
Therefore -(x<y) means
0 if x≥y
-1 if x<y
It is then used as a bit mask.
Edit
As suggested by Jonathan Leffler in comments, C has now a _Bool.
I made this small program to check what is it and how it is used:
#include <stdio.h>
int main() {
_Bool bFalse = 1>2;
printf("size of _Bool: %lu\nsize of comparison result: %lu\n", sizeof(bFalse), sizeof(1>2));
return 0;
}
This outputs:
size of _Bool: 1
size of comparison result: 4
In other words _Bool is one byte (a char), but it is not used as a result of Boolean comparisons (my compiler generates 4 bytes, that is, an int)
Note: tested with Clang on an Intel processor.
Edit: fix the types as kindly suggested in comments (and after checking the clang IR)
"if x < y, then -(x < y) will be all ones"
This is because, if x is less than y, condition evaluates to true (equal to 1). Notice the negetive sign before comparison, it makes the "1" of comparison result as "-1". In binary world, -1 has an all 1 representation, see Two's_complement. Example: 1111 1111 = -1.
However, if x > y, you get a -0 which is again all zero in binary.
Here, '<' is only a "x is_less_than y" comparison check, a logical operator.
I need to write a macro that would count bits in odd positions (in ANSI C). For example, in 1010 the count of such bits is 2 while in 0101 the count is 0.
This is the macro I came up with:
#include <stdio.h>
#define BIT_IN_BYTE 8
#define size(x,t) { \
int i, sum = 0; \
for(i = 0; x; x >>= 1) { \
if( (x & 1) && (i % 2) != 0) { \
sum++; \
} \
i++; \
} \
t = sum; \
} \
int main() {
int b = 44444, result;
size(b, result);
printf("count = %d\n", result);
return 0;
}
I have 2 questions really: whether I could've written the macro in a way that it wouldn't need two arguments in its signature and more importantly if there's a relatively simple way to extend the macro onto float and double types.
As in the comments to your question, using a macro here really is not good practice. You should really use a function instead - inline or otherwise.
Since you're apparently forced to use a macro in your case for reasons outside of your control, here are some relevant points to your example:
You can use sizeof to get the number of bytes in whatever type you pass in your x parameter. This will potentially allow you to generalize the macros to different types (you mention float and double) that have different sizes.
Since the macro does not do type checking, if you have something that works for int in a generic way - probably using bit-wise operations - you'll have a fighting chance of making it work for other types. I again note, however, that the lack of type safety is a reason to avoid macros in many cases.
As noted in a comment on your question, your current approach destroys the value in whatever you pass as parameter x. That's likely undesired and unnecessary.
You would only be able to avoid passing the second parameter if you can rewrite this such that is evaluates to a number. I'm not motivated to figure out exactly how to do that for this contrived example or if it is actually possible.