关于C11中持未对齐指针(用于标记指针)的合法性及相关问题的问询
Great question! Let's break this down step by step, since tagged pointers are such a useful optimization and the C11 standard's rules around misaligned pointers can be easy to misinterpret.
First, let's clarify the key distinction between the two pointer conversion scenarios you mentioned—this is where most people trip up:
- The example where you cast a misaligned
char*directly tostruct foo*(like(struct foo*)((char*)&f + 1)) is undefined behavior per C11 6.3.2.3p7, since that's an object-pointer-to-object-pointer conversion resulting in a misaligned pointer. - But your intended approach—converting a pointer to
uintptr_t, twiddling the bits (like|1), then converting back tostruct foo*—falls under C11 6.3.2.3p5 (integer-to-pointer conversions). The standard says this result is implementation-defined, not undefined. The only caveats here are:- The resulting pointer might be a trap representation (but most modern architectures don't treat misaligned pointers as traps unless you dereference them).
- You can't assume anything about the pointer's value beyond what your implementation documents (but for tagged pointer use cases, you just need to convert it back to the original integer later, which nearly all platforms support).
Now, to your core questions:
1. Is it well-defined to hold a misaligned pointer as long as you never dereference it?
Yes—if the pointer was created via a valid conversion path that doesn't trigger undefined behavior (like the integer-to-pointer route you're proposing). The C standard never says that merely holding or storing a misaligned pointer is undefined. Undefined behavior only kicks in when you perform an operation that requires alignment, like dereferencing the pointer, using it in va_arg, or passing it to a function that expects an aligned pointer (e.g., some platform-specific memory functions). As long as you only store it, pass it around, or convert it back to an integer, you're in implementation-defined territory (which is safe if your target platform supports this, as most do).
2. Is storing misaligned pointers for tagged pointers a valid approach (and better than using uintptr_t)?
Your analysis here is spot-on. Using a concrete pointer type (like struct foo*) to store your tagged pointer can indeed lead to better code generation compared to uintptr_t. Here's why:
- Strict aliasing rules let the compiler assume that
struct foo*doesn't alias with unrelated types likestruct bar*oruintptr_t. This lets the compiler do more aggressive optimizations (like keeping values in registers longer, or reordering operations) because it doesn't have to worry about unexpected aliasing. uintptr_t, on the other hand, is treated as a generic integer type that could alias with any pointer type. This forces the compiler to be more conservative, leading to potentially worse codegen.
That said, you do need to double-check your target platform's documentation:
- Make sure that integer-to-pointer conversions for misaligned addresses are not trap representations (most mainstream architectures—x86_64, ARM64, RISC-V—allow this).
- Ensure that when you convert the tagged pointer back to
uintptr_t, you get the original value you started with (again, this is standard on most platforms).
A quick note on magic pointers for switch statements
Your side question about using integer-constant-to-pointer conversions for magic switch cases is also valid, as long as your implementation defines that conversion. Some embedded platforms use this trick to create special sentinel values for switch cases, and it's safe as long as you never dereference those magic pointers.
Final takeaway
Your assessment is correct: storing misaligned pointers (created via integer-to-pointer conversion) for tagged pointer use cases is a valid approach, as long as you never dereference them. It's implementation-defined but not undefined behavior, and it can yield better codegen than using uintptr_t due to strict aliasing optimizations. Just make sure to verify your target platform's ABI or compiler documentation to confirm that misaligned pointers aren't trap representations.
内容来源于stack exchange

