E
Ed Morton
I have 2 counters - one is required to be a 2-byte variable while the
other is required to be 3 bytes (not my choice, but I'm stuck with it!).
I've declared them as:
unsigned short small;
unsigned long large: 24;
First question - is that the best way to declare the "large" one to
ensure it's 3 bytes? Another suggestion I got was "unsigned char
large[3];" but that would be a little tougher to do arithmetic
operations on.
Now I need a general-purpose macro to increment them and I need to be
able to produce a report if the counter would overflow when incremented.
So I don't need to have separate macros for each type of counter, I've
done this by introducing a temporary unsigned long (no counter will be
larger than that) to store the original and then doing the increment
using the real counter (to ensure that overflow occurs when expected for
that type of counter) then testing if it rolled over by seeing if the
result is less than the original as in the "incCntr()" macro below:
#include <stdio.h>
typedef struct {
unsigned short small;
unsigned long large: 24;
} CNTRS;
#define incCntr(cntr,incr) \
do { \
unsigned long _tmp = (unsigned long)(cntr); \
(cntr) = (cntr) + (incr); \
if ((cntr) < _tmp) { \
printf("Overflow at %lu + %d\n",_tmp,(incr));\
(cntr) = _tmp; \
} \
printf("%lu -> %lu\n",_tmp,(unsigned long)(cntr));\
} while(0)
int main(void)
{
CNTRS cntrs;
cntrs.small = 65529;
cntrs.large = 16777210;
incCntr(cntrs.small,5);
incCntr(cntrs.small,5);
incCntr(cntrs.large,5);
incCntr(cntrs.large,5);
return 1;
}
Second question - anyone see any problems with doing the overflow test
this way or can suggest a better alternative?
When compiling I get this warning:
gcc -Wall -otst tst.c
tst.c: In function `main':
tst.c:26: warning: long unsigned int format, unsigned int arg (arg 3)
tst.c:27: warning: long unsigned int format, unsigned int arg (arg 3)
It's complaining about the "cntr" argument in the line:
printf("%lu -> %lu\n",_tmp,(unsigned long)(cntr));
Third question - why is the compiler apparently ignoring my cast and
complaining that "(unsigned long)(cntr)" is an unsigned int?
Fourth question - would there be any reason not to declare my "small"
counter as an unsigned long bit-field too, i.e.:
unsigned long small: 16;
for consistency?
FWIW, the result of running the program is what I expected:
tst
65529 -> 65534
Overflow at 65534 + 5
65534 -> 65534
16777210 -> 16777215
Overflow at 16777215 + 5
16777215 -> 16777215
Regards,
Ed.
other is required to be 3 bytes (not my choice, but I'm stuck with it!).
I've declared them as:
unsigned short small;
unsigned long large: 24;
First question - is that the best way to declare the "large" one to
ensure it's 3 bytes? Another suggestion I got was "unsigned char
large[3];" but that would be a little tougher to do arithmetic
operations on.
Now I need a general-purpose macro to increment them and I need to be
able to produce a report if the counter would overflow when incremented.
So I don't need to have separate macros for each type of counter, I've
done this by introducing a temporary unsigned long (no counter will be
larger than that) to store the original and then doing the increment
using the real counter (to ensure that overflow occurs when expected for
that type of counter) then testing if it rolled over by seeing if the
result is less than the original as in the "incCntr()" macro below:
#include <stdio.h>
typedef struct {
unsigned short small;
unsigned long large: 24;
} CNTRS;
#define incCntr(cntr,incr) \
do { \
unsigned long _tmp = (unsigned long)(cntr); \
(cntr) = (cntr) + (incr); \
if ((cntr) < _tmp) { \
printf("Overflow at %lu + %d\n",_tmp,(incr));\
(cntr) = _tmp; \
} \
printf("%lu -> %lu\n",_tmp,(unsigned long)(cntr));\
} while(0)
int main(void)
{
CNTRS cntrs;
cntrs.small = 65529;
cntrs.large = 16777210;
incCntr(cntrs.small,5);
incCntr(cntrs.small,5);
incCntr(cntrs.large,5);
incCntr(cntrs.large,5);
return 1;
}
Second question - anyone see any problems with doing the overflow test
this way or can suggest a better alternative?
When compiling I get this warning:
gcc -Wall -otst tst.c
tst.c: In function `main':
tst.c:26: warning: long unsigned int format, unsigned int arg (arg 3)
tst.c:27: warning: long unsigned int format, unsigned int arg (arg 3)
It's complaining about the "cntr" argument in the line:
printf("%lu -> %lu\n",_tmp,(unsigned long)(cntr));
Third question - why is the compiler apparently ignoring my cast and
complaining that "(unsigned long)(cntr)" is an unsigned int?
Fourth question - would there be any reason not to declare my "small"
counter as an unsigned long bit-field too, i.e.:
unsigned long small: 16;
for consistency?
FWIW, the result of running the program is what I expected:
tst
65529 -> 65534
Overflow at 65534 + 5
65534 -> 65534
16777210 -> 16777215
Overflow at 16777215 + 5
16777215 -> 16777215
Regards,
Ed.