Both implementations are probably equally efficient, but the second one is uglier and more bug-prone, so I would suggest to avoid it.
On first glance, your second implementation appears more efficient because in the first one, the code needs to add a small offset to the pointer before dereferencing it. However, since such code is extremely common, modern processors usually support dereferencing with an offset as a single instruction. For example in x86 assembly, you can add a constant offset to a pointer stored in a register when dereferencing it with the MOV
instruction.
However, the fact that the offset and dereference happens in a single instruction doesn't prove that it is exactly as quick as a single instruction that doesn't need an offset. The x86 instruction set is full of instructions which take different amount of cycles depending on their operands. I found an earlier stackoverflow answer Do complex addressing modes have extra overhead for loads from memory? which suggests that the offset is already part of the most basic and quickest variant of MOV
, and only more complex addressing (such as needing to add two registers together) makes dereferencing a tiny bit slower.
So all-in-all, I would choose the first option. It's much clearer, less error-prone, and probably identically efficient. And if you're not sure, you can always measure it for yourself and report back here.