Appendix A: Data Types and Compatibility
As we consider data types in C and how they are compatible with each other, let's recall the rules of compatibility. Here are a few notes:
- C uses static typing, which dictates that the types of variables are derived once (at declaration) and do not change throughout the execution of a program.
- C uses strong typing, which means that once variables are bound to a data type (at declaration), they stay bound to that type. They cannot not change types, but require values to be converted to their data type before they are assigned.
- In general, type A is compatible with type B when (a) the operations of A are also the operations of B and (b) the values that variables of type A can have are at least a subset of the values that variables of type B can have.
- Type modifiers have an effect on the values that a variable can take on and, thus, affect type compatibility.
The table below contains modifiers where appropriate. These modifiers are:
- "signed" and "unsigned": This determines the capability to represent negative numbers. Unsigned types are not wider than signed types, but they represent different number ranges.
- "short": This typically specifies a width that is half of the type it modifies.
- "long": This modifier represents a width double the width of the type it modifies.
Type | Description | Compatibility |
char |
Single byte units with characters as their value. On Pebble OS, these values come from the Unicode character set. While characters can be converted to integers, they do not have a sign bit. This means the integer range is 0 to 255. | Any numeric type |
signed char |
Single byte units, represented as integers. Signed char types have a range from -127 to 128. | Any numeric type |
unsigned char |
Single byte units, represented as numbers without a sign bit. This is the same as the `char` type. Integer range is 0 to 255. | Any numeric type |
int signed signed int |
Representation of standard integer. On Pebble OS, this type is 32 bits wide and uses 2's complement for negative representation. Range is -231-1 to +231. | Any numeric type |
short short int signed short signed short int |
Representation of a signed integer. It is usually half the width of integers; on Pebble OS, this is 16 bits. Range is -32,767 to 32,768. Uses 2's complement for negative representation. | Any numeric type |
unsigned short unsigned short int |
Representation of an unsigned integer. It is usually half-width with no sign; on Pebble OS, this is 16 bits. Range is 0 to 65,535. | Any numeric type |
long long int signed long signed long int |
This represents a signed double width integer. On Pebble OS, the width is the same as signed integers: 32 bits (which is allowed by the C standard). Range is -231-1 to +231. It uses 2's complement for negative representation. | Any numeric type |
unsigned long unsigned long int |
Representation of an unsigned long integer. This is usually double the width of an unsigned integer, however on Pebble OS this is 32 bits. Range is 0 to +232-1. | Any numeric type |
long long long long int signed long long signed long long int |
This represents a signed double long integer. It can be double to quad width; on Pebble OS, it is 64 bits. Range is -263-1 to +263 Uses 2's complement for negative representation. | Any numeric type |
unsigned long long unsigned long long int |
Representation of an unsigned double long integer. This is usually double the long width; on Pebble OS, this means 64 bits. Range is 0 to +264-1. | Any numeric type |
float |
Single precision floating point number, 32 bits wide in IEEE 754 format. All float types are signed. | Other float types |
double |
Double precision floating point number. 64 bits wide in IEEE 754 format for double precision numbers. All float types are signed. | Other float types |
long double |
Extended, or quadruple, precision floating point numbers, 128 bits wide in IEEE 754 format for quadruple precision numbers. All float types are signed. | Other float types |
_Bool bool |
Represents boolean values. Includes macros for true and false . Part of the C standard, but not included in Pebble SDKs. |
numeric types |
We can write a smartwatch app to see how these definitions are implemented on a Pebble smartwatch. You can view and run the code yourself in CloudPebble with this link, but the relevant snippet is shown below. The output is done using the APP_LOG
macro.
static void display_chars() {
APP_LOG(APP_LOG_LEVEL_INFO, "\nCHARACTER SIZES\n char = %d, max char = %d\n unsigned char = %d",
sizeof(char), CHAR_MAX, sizeof(unsigned char));
}
static void display_integers() {
APP_LOG(APP_LOG_LEVEL_INFO, "\nINTEGER SIZES\n short = %d, max short = %d\n int = %d, max int = %d",
sizeof(short int), SHRT_MAX, sizeof(int), INT_MAX);
APP_LOG(APP_LOG_LEVEL_INFO, "\n unsigned short = %d, max unsigned short = %d",
sizeof(unsigned short int), USHRT_MAX);
APP_LOG(APP_LOG_LEVEL_INFO, "\n unsigned int = %d, unsigned max int = %u",
sizeof(unsigned int), UINT_MAX);
APP_LOG(APP_LOG_LEVEL_INFO, "\n long = %d, max long = %li\n long long = %d, max long long = %lli",
sizeof(long), LONG_MAX, sizeof(long long), LLONG_MAX);
APP_LOG(APP_LOG_LEVEL_INFO, "\n unsigned long = %d, unsigned max long = %lu",
sizeof(unsigned long), ULONG_MAX);
APP_LOG(APP_LOG_LEVEL_INFO, "\n unsigned long long = %d, max unsigned long long = %llu",
sizeof(long long), ULLONG_MAX);
}
The code measures size of each type by using the sizeof()
operator, which measures in bytes. The output of display_chars()
is given below (cleaned up from the log display) and shows that character and unsigned character types match up with the table above. Both are single bytes wide.
CHARACTER SIZES
char = 1, max char = 255
unsigned char = 1
The size of short and regular integers, as well as the maximum values, are also in line with the table above. As we described, there is no difference long integers and regular integers. The size and max value of regular integers and long integers (and their unsigned counterparts) are the same. Based on long integers, long long integers are on track: double the size and their max values match accordingly. The output for display_integers()
is below:
INTEGER SIZES
short = 2, max short = 32767
int = 4, max int = 2147483647
unsigned short = 2, max unsigned short = 65535
unsigned int = 4, unsigned max int = 4294967295
long = 4, max long = 2147483647
long long = 8, max long long = 92233720368547758
unsigned long = 4, unsigned max long = 4294967295
unsigned long long = 8, max unsigned long long = 18446744073709551615
Notice that we did not compute the max values, but rather used defined constants. Every C compiler has a set of constants defined that outline the maximum values for that installation.
Also note that we did not test floating point numbers. As pointed out in Chapter 3, floating point numbers are difficult for small embedded processors like those in Pebble smartwatches.