concept unsigne char in category c
Table 3.1. Scalar types used in this book (view table figure)
Level
Name
Other
Category
Where
printf
0 size_t Unsigned <stddef.h> "%zu" "%zx" 0 double Floating Built in "%e" "%f" "%g" "%a" 0 signed int Signed Built in "%d" 0 unsigned Unsigned Built in "%u" "%x" 0 bool _Bool Unsigned <stdbool.h> "%d" as 0 or 1 1 ptrdiff_t Signed <stddef.h> "%td" 1 char const* String Built in "%s" 1 char Character Built in "%c" 1 void* Pointer Built in "%p" 2 unsigned char Unsigned Built in "%hhu" "%02hhx"
Even though generally all objects are typed, the memory model makes another simplification: that all objects are an assemblage of bytesC. The sizeof operator that we introduced in the context of arrays measures the size of an object in terms of the bytes that it uses. There are three distinct types that by definition use exactly one byte of memory: the character types char, unsigned char, and signed char.
Let us first try to figure out what values we would expect for the individual bytes. In a slight abuse of language, let us speak of the different parts of an unsigned number that correspond to the bytes as representation digits. Since we view the bytes as being of type unsigned char, they can have values 0 . . . UCHAR_MAX, inclusive, and thus we interpret the number as written with a base of UCHAR_MAX+1. In the example, on my machine, a value of type unsigned can be expressed with sizeof(unsigned) == 4 such representation digits, and I chose the values 0xAA, 0xBB, 0xCC, and 0xDD for the highest- to lowest-order representation digit. The complete unsigned value can be computed using the following expression, where CHAR_BIT is the number of bits in a character type:
1 ((0xAA << (CHAR_BIT*3)) 2 |(0xBB << (CHAR_BIT*2)) 3 |(0xCC << CHAR_BIT) 4 |0xDD) !@%STYLE%@! {"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":1}],[{\"line\":0,\"ch\":15},{\"line\":0,\"ch\":23}],[{\"line\":1,\"ch\":19},{\"line\":1,\"ch\":27}],[{\"line\":2,\"ch\":18},{\"line\":2,\"ch\":26}],[{\"line\":1,\"ch\":0},{\"line\":1,\"ch\":1}],[{\"line\":0,\"ch\":15},{\"line\":0,\"ch\":23}],[{\"line\":1,\"ch\":19},{\"line\":1,\"ch\":27}],[{\"line\":2,\"ch\":18},{\"line\":2,\"ch\":26}],[{\"line\":0,\"ch\":24},{\"line\":0,\"ch\":25}],[{\"line\":2,\"ch\":0},{\"line\":2,\"ch\":1}],[{\"line\":0,\"ch\":15},{\"line\":0,\"ch\":23}],[{\"line\":1,\"ch\":19},{\"line\":1,\"ch\":27}],[{\"line\":2,\"ch\":18},{\"line\":2,\"ch\":26}],[{\"line\":3,\"ch\":0},{\"line\":3,\"ch\":1}]]"} !@%STYLE%@!With the union defined earlier, we have two different facets to look at the same twofold object: twofold.val presents it as being an unsigned, and twofold.bytes presents it as an array of unsigned char. Since we chose the length of twofold.bytes to be exactly the size of twofold.val, it represents exactly its bytes, and thus gives us a way to inspect the object representationC of an unsigned value: all its representation digits:
This starts with a declaration of a union similar to what we saw earlier. Again, we have a data object (of type complex double[2] in this case) that we overlay with an array of unsigned char. Other than the fact that this part is a bit more complex, at first glance there is no major problem with it. But if I execute this program on my machine, I get