> Are brainfuck[1] or malbolge[2] sane?
In that they are sound and consistent, yes, any esoteric language is sane. Merely esoteric.
> I'm not sure, that it is possible to be a good C programmer and to not have any clue of what the compiler will produce...
The compiler is under no requirement to pack structures in a specific way, or under any requirement to produce accesses in a cache pattern that mirrors your intent in the code. The compiler is required to produce a very specific set of observable behaviors, specifically:
> Volatile accesses to objects are evaluated strictly according to the rules of the abstract machine.
> At program termination, all data written into files shall be identical to the result that execution
of the program according to the abstract semantics would have produced.
> The input and output dynamics of interactive devices shall take place as specified in 7.23.3. The intent of these requirements is that unbuffered or line-buffered output appear as soon as possible, to ensure that prompting messages appear prior to a program waiting for input.
And that's it. When thinking about the correctness of one's code, things like layout and cache access patterns are irrelevant because the abstract machine does not provide for such things. Thinking in that frame can only lead to errors.
Now, as a fully separate and apart lens to view one's code, of course performance matters. Of course struct layout (as guaranteed by ABI standards like SysV and Windows) matters, of course you should make the optimizer's job easier by doing sequential rather than scattered accesses. That's true of any programming language.
It's true for COBOL and Go and Ada, and yet when using those languages one does not try to reason about accessing objects via incompatible lvalues like C programmers often try to do. This machine-optimization frame of thinking is not a frame you can use to think about the behavior of the program with, behavior needs to be conceived in the frame of the abstract machine.