kid joe wrote:
Hi
What's the best way in C to access the processor's flags register? I'm
thinking particularly of checking the carry or overflow flag after an
arithmetic operation.
There's no "best way" because as far as C is concerned
there's no way at all. One tiny problem is that C can be
(and has been) implemented on machines that have no flags.
Unfortunately, this leaves the C programmer in a bit of a
bind when it comes to overflow detection. For some operations
on some data types you can inspect the results to determine
whether there was an overflow. For example,
unsigned int ua = ..., ub = ...;
unsigned int sum = ua + ub;
if (sum >= ua) {
/* the mathematical sum was in representable range */
}
else {
/* the sum was out of range and has been reduced */
}
However, this approach won't necessarily work for all types.
For signed integers an overflow can produce fatal (or at least
unwelcome) effects as soon as it occurs, so you can't wait until
afterwards: You need to prevent it from happening in the first
place. That leads to ugly code like
int sa = ..., sb = ...;
int sum;
if (sa >= 0) {
if (sb <= INT_MAX - sa)
sub = sa + sb;
else {
/* sum would be too large */
}
}
else {
if (sb >= sa - INT_MIN)
sum = sa + sb;
else {
/* sum would be too small */
}
}
In actual practice it's rare to see code of this sort even
in a few places, and you'll just never see it applied everywhere
in a program! What people usually do, for better or worse, is
choose data types that will (they think) be able to handle the
expected range of data without overflowing, and then cross their
fingers and pretend overflow can never happen. Often they're
right, but the results can be spectacular when they're wrong ...
Some C compilers on some machines provide non-portable
extensions to get at such information (plus some promises on
how overflows are handled, so the information can be useful).
Note, though, that just "reading the flags register" is most
likely not sufficient, since you'd need to check it after each
potentially problematic operation:
y = ((a * x + b) * x) + c;
if (overflow_flag_is_set()) /* sorry; too late */
/* instead: */
y = a * x;
if (overflow_flag_is_set()) ...
y += b;
if (overflow_flag_is_set()) ...
y *= x;
if (overflow_flag_is_set()) ...
y += c;
if (overflow_flag_is_set()) ...
What would be Really Nice would be a "latching flag" that would
be set by any overflow and remain set until explicitly cleared:
clear_overflow_latch();
y = ((a * x + b) * x) + c;
if (overflow_latch_is_set()) ...
However, there's no such thing -- not even a "volatile" flag --
in C itself, presumably because it would be punishingly slow
to provide on many machines. (C follows the long-established
tradition that speed is more important than correctness. ;-)
--
Er*********@sun.com