One of the odder things about C is that one is not always, well, one.
For instance, consider this output:
$ ./woisno x0 = 5, x0 + 1 = 6 x1 = 5, x1 + 1 = 7 x2 = 5, x2 + 1 = 13 x3 = 5, x3 + 1 = 165
It's not a trick of fake output: here's the C code that generated that:
printf("x0 = %lu, x0 + 1 = %lu\n",(uint64_t)x0,(uint64_t)(x0+1)); printf("x1 = %lu, x1 + 1 = %lu\n",(uint64_t)x1,(uint64_t)(x1+1)); printf("x2 = %lu, x2 + 1 = %lu\n",(uint64_t)x2,(uint64_t)(x2+1)); printf("x3 = %lu, x3 + 1 = %lu\n",(uint64_t)x3,(uint64_t)(x3+1));
So what *is* going on?
It's a matter of types:
struct x3_x3 { char *arr[20]; }; uint64_t x0 = 5; uint16_t *x1 = (uint16_t *)5; uint64_t *x2 = (uint64_t *)5; struct x3_x3 *x3 = (struct x3_x3 *)5;
What is happening is the unusual rule that adding to a pointer type in C is actually done on the size of whatever is being pointed at. Kernighan and Richie's classic "The C Programming Language" reveals this, appropriately enough, in the chapter "Pointers and Arrays." Here's the key sentence: 'The meaning of "adding 1 to a pointer," and by extension, all pointer arithmetic, is that pa + 1 points to the next object, and pa + i points to the i-th object beyond pa.'
They continue with "[t]he correspondence between indexing and pointer arithmetic is very close. By definition, the value of a variable or expression of type array is the address of element zero of the array. Thus after the assignment pa = &a[0]; pa and a have identical values."