Ten hours on schemes for holding numbers. Most of the bytes on your machine are not numbers at all.
/* 01-fourways.c */ #include <stdio.h> #include <string.h> int main(void) { unsigned pattern = 0x434F4421; int i; float f; char c[5] = { 0 }; memcpy(&i, &pattern, 4); memcpy(&f, &pattern, 4); memcpy(c, &pattern, 4); printf("as hex 0x%08X\n", pattern); printf("as an int %d\n", i); printf("as a float %g\n", f); printf("as text %c%c%c%c\n", c[3], c[2], c[1], c[0]); return 0; }
/* 02-ascii.c */ #include <stdio.h> int main(void) { char c[] = { '0', '9', 'A', 'Z', 'a', 'z', ' ', '~' }; printf("char value hex bits\n"); for (int i = 0; i < 8; i++) { printf(" %c %5d 0x%02X ", c[i], c[i], c[i]); for (int b = 7; b >= 0; b--) putchar(c[i] >> b & 1 ? '1' : '0'); putchar('\n'); } printf("\n'A' is %d and 'a' is %d. " "the difference is %d.\n", 'A', 'a', 'a' - 'A'); return 0; }
c - '0' gives the value./* 03-case.c */ #include <stdio.h> #include <ctype.h> int main(void) { char c[] = { 'A', 'Z', 'a', 'z', '0', '5', ' ', '@' }; printf("char value flip bit 5 becomes\n"); for (int i = 0; i < 8; i++) { int x = c[i] ^ 32; printf(" %c %5d %10d %c\n", c[i], c[i], x, isprint(x) ? x : '?'); } printf("\nfor letters, one bit is the whole difference " "between\nupper and lower case. " "for anything else it is nonsense.\n"); return 0; }
/* 04-hex.c */ #include <stdio.h> int main(void) { unsigned v = 0xB4C2; printf("value 0x%04X\n\n", v); printf("hex digit four bits\n"); for (int shift = 12; shift >= 0; shift -= 4) { unsigned nib = v >> shift & 0xF; printf(" %X ", nib); for (int b = 3; b >= 0; b--) putchar(nib >> b & 1 ? '1' : '0'); putchar('\n'); } printf("\nall sixteen bits: "); for (int b = 15; b >= 0; b--) putchar(v >> b & 1 ? '1' : '0'); return 0; }
ASCII used seven bits of an eight bit byte, leaving 128 spare patterns. Every country claimed them, and every country claimed them differently.
India built its own: ISCII, IS 13194:1991, one eight bit table covering Devanagari, Bengali, Gurmukhi, Gujarati, Odia, Tamil, Telugu, Kannada and Malayalam.
/* 05-utf8.c */ #include <stdio.h> #include <string.h> void dump(char *label, char *s) { printf("%-10s %2zu bytes ", label, strlen(s)); for (int i = 0; s[i]; i++) printf("%02X ", (unsigned char)s[i]); printf("\n"); } int main(void) { dump("hello", "hello"); dump("namaste", "नमस्ते"); dump("kannada", "ಕನ್ನಡ"); dump("tamil", "தமிழ்"); dump("rupee", "₹"); return 0; }
न is E0 A4 A8, which is 11100000, 10100100, 10101000.
A three byte start, then two continuations. Any byte beginning 10 is never the start of anything.
/* 06-count.c */ #include <stdio.h> #include <string.h> int points(char *s) /* count start bytes */ { int n = 0; for (int i = 0; s[i]; i++) if (((unsigned char)s[i] & 0xC0) != 0x80) n++; return n; } int main(void) { char *t[] = { "hello", "भारत", "नमस्ते", "क्ष", "ಕನ್ನಡ" }; int eye[] = { 5, 3, 3, 1, 3 }; /* what a reader counts */ printf("text bytes code points letters you see\n"); for (int i = 0; i < 5; i++) printf("%-10s %5zu %11d %d\n", t[i], strlen(t[i]), points(t[i]), eye[i]); return 0; }
/* 07-rupee.c */ #include <stdio.h> #include <string.h> int main(void) { char *old = "Rs. 1500"; char *new = "₹1500"; printf("%-10s %2zu bytes\n", old, strlen(old)); printf("%-10s %2zu bytes\n\n", new, strlen(new)); printf("the rupee sign is one character, U+20B9, " "three bytes in UTF-8:\n "); for (int i = 0; i < 3; i++) printf("%02X ", (unsigned char)new[i]); return 0; }
Unsigned, two's complement, fixed point, IEEE 754, ASCII, UTF-8. Six agreements about the same bits, and the bits are identical in all six.
Next session closes the arc. Everything you can now write down, and the one thing you still cannot do with any of it.