Avoiding Overflow Errors in Keil C51 Large Integer Constants

The default integer constant operations in the C51 compiler may lead to overflow errors. To avoid potential calculation errors, the data type of large integers should be specified.

Keil C51 is a compiler compatible with ANSI C. The ANSI C standard specifies that the default data types for decimal integer constants are one of int, long int, and unsigned long int. The actual size of the constant determines which type is applied. If the constant falls within the range of -32768 to 32767, it is treated as int. If treating it as int results in overflow, long int or the larger data type unsigned long int should be considered. In summary, the compiler always specifies the type of the constant based on what is feasible.

However, this principle does not always work. When two constants are operated on, it may lead to overflow. For example:

#define SYSCLK 22118400 // SYSCLK in Hz (22.1184 MHz external crystal oscillator)

#define SLIDER_REST_TIME 100 // in ms, slider rest time

#define REST_DELAY SYSCLK * SLIDER_REST_TIME / (65536 * 1000)

unsigned char i;

i = REST_DELAY;

In Keil C51, the value of i is 0xE1, which is 225, not the expected result of 22118400 * 100 / (65536 * 1000) = 33.75, rounded down to 33. The analysis of the cause is as follows:

After macro replacement: i = 22118400 * 100 / (65536 * 1000); The compiler first defines the type for 22118400. Since 22118400 is not within the range of int, but is within the range of long int (-2147483648 to 2147483647), it is treated as a long int. During the multiplication operation, 100 is automatically treated as long int, and the multiplication 22118400 * 100 is performed as two signed long integer constants. The result remains a signed long integer, which is represented in hexadecimal as 0x83D60000 and in decimal as -2083127296. Clearly, an overflow error has occurred. The Keil compiler does not provide any error or warning messages (VC++6.0 gives warning C4307: ‘*’ : integral constant overflow), and continues to the next operation 65536 * 1000, which results in a signed long integer with a hexadecimal representation of 0x3E80000 and a decimal value of 65536000. Finally, the division of -2083127296 by 65536000 is calculated as two long integer divisions, resulting in 0xFFFFFFE1. Since i is of character type, the least significant byte of 0xFFFFFFE1 is taken as 0xE1, assigning this value to i, resulting in the final value of i being 0xE1.

The solution to this overflow error, using a term from C language, is “promotion.” In the above example, this means specifying 22118400 as an unsigned long integer, i.e.,

#define SYSCLK 22118400UL

Note: Although specifying any one of the constants 22118400, 100, 65536, or 1000 as an unsigned long integer will yield the correct result, for the sake of readability and standardization, it is advisable to specify the type for the larger integer.

Conclusion: The default integer constant operations in the C51 compiler may lead to overflow errors. To avoid potential calculation errors, the data type of large integers should be specified.Avoiding Overflow Errors in Keil C51 Large Integer Constants

Leave a Comment