Effective type determines which type may be used to access an object. For a declared variable or compound literal, it is the declared type. Storage returned by malloc starts uninitialized and typeless; assigning through an lvalue gives its elements an effective type and a value. section 12.6 section 13.1
Establishing type in allocated storage
size_t length = livingPeople(); double* largeVec = malloc(length * sizeof *largeVec); for (size_t i = 0; i < length; ++i) { largeVec[i] = 0.0; } free(largeVec); The assignments make the allocated elements double objects. The declaration of largeVec supplies the pointer type, not an effective type for the storage it points to. section 13.1
Apply these access rules:
- Access an object through its effective type or through a pointer to a character type. section 12.6
- Access a declared variable or compound literal through its declared type or a character-type pointer; its type cannot be changed. section 12.6
- Read any object representation as unsigned char, but do not read an unsigned-char array through another type; doing so leaves the program state undefined. section 12.6
- Union objects are an exception: access any member when the resulting byte representation is a valid value of the access type. section 12.6
unsigned char A[sizeof(unsigned)] = { 9 };
// Valid but useless, as most casts are
unsigned* p = (unsigned*)A;
// Error: access with a type that is neither the effective type nor a
// character type
printf("value %u\n", *p);
Inspect the contrast between forming an unsigned-pointer cast and actually dereferencing it: the cast is shown as valid, while the incompatible access is not. section 12.6

