MingW-w64编译OpenEXR:C++98兼容的16字节指针对齐检查方案
Great question—dealing with pointer alignment in C98 while avoiding C11 features can be tricky, but there are solid, compiler-agnostic ways to fix this without breaking compatibility. Let's break down the problem and solutions step by step.
First, let's clarify why you're seeing that error:
On 64-bit MinGW-w64,
unsigned longis a 32-bit type, but your pointer is 64-bit. Casting a 64-bit pointer to a 32-bit integer truncates the upper bits, which GCC correctly flags as a precision loss. Usinguintptr_tfixes it, but since that's a C11 addition (it originated in C99 but wasn't standardized in C until 2011), you're right to worry about compatibility with older compilers.
Solution 1: Conditional Typedef for Platform-Specific Integer Size
This approach uses C++98-standard types and conditional compilation to define an integer type that can safely hold a pointer value on any platform:
// Define a type that can safely hold a pointer value in C++98 #ifdef _WIN64 typedef unsigned long long uintptr_compat_t; #elif defined(__x86_64__) || defined(__ppc64__) || defined(__aarch64__) typedef unsigned long long uintptr_compat_t; #else // For 32-bit systems, unsigned long is sufficient typedef unsigned long uintptr_compat_t; #endif bool isPointerAlignedTo16(const void* __restrict__ pPointer) { uintptr_compat_t addr = reinterpret_cast<uintptr_compat_t>(pPointer); return (addr & 15) == 0; }
Why this works:
unsigned long longis supported by most compilers even in C98 mode (it was a common extension before C11 standardized it).- The conditional checks target major 64-bit platforms, ensuring we use a 64-bit integer for 64-bit pointers, and a 32-bit integer for 32-bit systems.
reinterpret_castis the correct cast for converting pointers to integers in C++98 (static_cast is not allowed here, which is why your earlier attempt withstatic_cast<unsigned long>failed).
Solution 2: Compiler-Builtin Alignment Checks (Simpler, Less Portable)
If you're okay with relying on widely supported compiler-specific builtins, you can use functions designed explicitly for alignment checks:
bool isPointerAlignedTo16(const void* __restrict__ pPointer) { #ifdef __GNUC__ // GCC, Clang, MinGW-w64 return __builtin_is_aligned(pPointer, 16); #elif _MSC_VER // MSVC return ((unsigned long long)pPointer & 15) == 0; #else // Fallback for other compilers (assumes 32-bit or compiler supports long long) return ((unsigned long)pPointer & 15) == 0; #endif }
Why this works:
__builtin_is_alignedis a GCC/Clang builtin that directly checks alignment without manual integer casting.- For MSVC, we use a 64-bit integer cast since MSVC's
unsigned long longis supported in C++98 mode. - The fallback covers older 32-bit compilers where
unsigned longis large enough for pointers.
Key Notes for Strict C++98 Compliance
If you need to avoid unsigned long long entirely (for extremely old compilers that don't support the extension), you can use a union-based approach (note: reading an unused union member is technically undefined behavior in C++98, but it works reliably in most mainstream compilers):
union PointerAlignChecker { const void* ptr; unsigned long ul; #if defined(_WIN64) || defined(__x86_64__) unsigned long long ull; #endif }; bool isPointerAlignedTo16(const void* __restrict__ pPointer) { PointerAlignChecker checker; checker.ptr = pPointer; #ifdef _WIN64 return (checker.ull & 15) == 0; #elif defined(__x86_64__) return (checker.ull & 15) == 0; #else return (checker.ul & 15) == 0; #endif }
内容的提问来源于stack exchange,提问作者galinette

