On 2026-03-16 01:37, Bruno Haible wrote:
While I understand the purpose of namespace cleanliness — so that the compiler can tell the programmer that a '#include <stdint.h>' (in this case) is missing —, I think of it as a secondary goal that we rarely can achieve, and the introduced complexity is starting to be greater than the benefit.
Yes, it's a tradeoff, and opinions can differ about tradeoffs.My opinion is partly colored by glibc, which must be namespace clean. It's not simply the desire to make code shareable (unlikely here); it's a matter of priorities and style. Namespace cleanliness is helpful when developing on GNU (to help check that the code is portable); it's less important when building on non-GNU systems. Hence when feasible Gnulib should be as namespace-clean as glibc when Gnulib interposes its own .h file in front of glibc's, as it does here.
+# define _GL_STDBIT_UINT_FAST64 __UINT_FAST64_TYPE__The GCC documentation [1] says about these macros: "You should not use these macros directly; instead, include the appropriate headers and use the typedefs."
That's good advice in general, but when implementing standard headers Gnulib can disregard it for the same reason glibc does. E.g., see glibc's <inttypes.h>, which uses __WCHAR_TYPE__. GCC and Clang won't change the macros' meaning, so it's safe to use them. And in the unlikely event that the macros are withdrawn, Gnulib stdbit.h will still build and run.
If the intent is to convert a value of type 'unsigned char' to an 'uint_fast16_t', a cast is the perfect, understandable way of doing so. Writing it as an ' | zero' is intentional obfuscation.
It's understandable, but it's not perfect. The cast is too powerful, as it can also convert a pointer or a float and typos like that won't be statically checked.
What was your rationale for avoiding casts in the first place? Does it apply here, in the situation of converting an integer to another integer type?
Yes, as I want to catch typos when the argument happens to not be an integer. But I take your point that I used a less-than-obvious circumlocution. I installed the attached patch, which uses a different approach that I hope makes the code easier to follow, in the sense that the castless conversions are more obvious.
From cbfda6326c3015f0d5c05c736ae9ea1a9350608a Mon Sep 17 00:00:00 2001 From: Paul Eggert <[email protected]> Date: Mon, 16 Mar 2026 09:10:00 -0700 Subject: [PATCH] stdbit-h: be clearer about castless conversion * lib/stdbit.in.h (stdc_load8_beu16, stdc_load8_beu32) (stdc_load8_beu64, stdc_load8_leu16, stdc_load8_leu32) (stdc_load8_leu64): Assign to temporaries rather than ORing to zero. --- ChangeLog | 7 +++++++ lib/stdbit.in.h | 56 +++++++++++++++++++------------------------------ 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5c38bcab4c..314b7b1374 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2026-03-16 Paul Eggert <[email protected]> + + stdbit-h: be clearer about castless conversion + * lib/stdbit.in.h (stdc_load8_beu16, stdc_load8_beu32) + (stdc_load8_beu64, stdc_load8_leu16, stdc_load8_leu32) + (stdc_load8_leu64): Assign to temporaries rather than ORing to zero. + 2026-03-16 Bruno Haible <[email protected]> stdc_rotate_left, stdc_rotate_right: Update documentation. diff --git a/lib/stdbit.in.h b/lib/stdbit.in.h index 8f70855615..54df8f3690 100644 --- a/lib/stdbit.in.h +++ b/lib/stdbit.in.h @@ -1521,33 +1521,27 @@ stdc_load8_beu8 (const unsigned char ptr[1]) _GL_STDC_LOAD8_INLINE uint_least16_t stdc_load8_beu16 (const unsigned char ptr[2]) { - _GL_STDBIT_UINT_FAST16 zero = 0; - return (((ptr[0] | zero) << (8 * 1)) - | ((ptr[1] | zero) << (8 * 0))); + _GL_STDBIT_UINT_FAST16 v0 = ptr[0], v1 = ptr[1]; + return (v0 << (8 * 1)) | (v1 << (8 * 0)); } _GL_STDC_LOAD8_INLINE uint_least32_t stdc_load8_beu32 (const unsigned char ptr[4]) { - _GL_STDBIT_UINT_FAST32 zero = 0; - return (((ptr[0] | zero) << (8 * 3)) - | ((ptr[1] | zero) << (8 * 2)) - | ((ptr[2] | zero) << (8 * 1)) - | ((ptr[3] | zero) << (8 * 0))); + _GL_STDBIT_UINT_FAST32 v0 = ptr[0], v1 = ptr[1], v2 = ptr[2], v3 = ptr[3]; + return (v0 << (8 * 3)) | (v1 << (8 * 2)) | (v2 << (8 * 1)) | (v3 << (8 * 0)); } _GL_STDC_LOAD8_INLINE uint_least64_t stdc_load8_beu64 (const unsigned char ptr[8]) { - _GL_STDBIT_UINT_FAST64 zero = 0; - return (((ptr[0] | zero) << (8 * 7)) - | ((ptr[1] | zero) << (8 * 6)) - | ((ptr[2] | zero) << (8 * 5)) - | ((ptr[3] | zero) << (8 * 4)) - | ((ptr[4] | zero) << (8 * 3)) - | ((ptr[5] | zero) << (8 * 2)) - | ((ptr[6] | zero) << (8 * 1)) - | ((ptr[7] | zero) << (8 * 0))); + _GL_STDBIT_UINT_FAST64 + v0 = ptr[0], v1 = ptr[1], v2 = ptr[2], v3 = ptr[3], + v4 = ptr[4], v5 = ptr[5], v6 = ptr[6], v7 = ptr[7]; + return ((v0 << (8 * 7)) | (v1 << (8 * 6)) + | (v2 << (8 * 5)) | (v3 << (8 * 4)) + | (v4 << (8 * 3)) | (v5 << (8 * 2)) + | (v6 << (8 * 1)) | (v7 << (8 * 0))); } _GL_STDC_LOAD8_INLINE uint_least8_t @@ -1559,33 +1553,27 @@ stdc_load8_leu8 (const unsigned char ptr[1]) _GL_STDC_LOAD8_INLINE uint_least16_t stdc_load8_leu16 (const unsigned char ptr[2]) { - _GL_STDBIT_UINT_FAST16 zero = 0; - return (((ptr[0] | zero) << (8 * 0)) - | ((ptr[1] | zero) << (8 * 1))); + _GL_STDBIT_UINT_FAST16 v0 = ptr[0], v1 = ptr[1]; + return (v0 << (8 * 0)) | (v1 << (8 * 1)); } _GL_STDC_LOAD8_INLINE uint_least32_t stdc_load8_leu32 (const unsigned char ptr[4]) { - _GL_STDBIT_UINT_FAST32 zero = 0; - return (((ptr[0] | zero) << (8 * 0)) - | ((ptr[1] | zero) << (8 * 1)) - | ((ptr[2] | zero) << (8 * 2)) - | ((ptr[3] | zero) << (8 * 3))); + _GL_STDBIT_UINT_FAST32 v0 = ptr[0], v1 = ptr[1], v2 = ptr[2], v3 = ptr[3]; + return (v0 << (8 * 0)) | (v1 << (8 * 1)) | (v2 << (8 * 2)) | (v3 << (8 * 3)); } _GL_STDC_LOAD8_INLINE uint_least64_t stdc_load8_leu64 (const unsigned char ptr[8]) { - _GL_STDBIT_UINT_FAST64 zero = 0; - return (((ptr[0] | zero) << (8 * 0)) - | ((ptr[1] | zero) << (8 * 1)) - | ((ptr[2] | zero) << (8 * 2)) - | ((ptr[3] | zero) << (8 * 3)) - | ((ptr[4] | zero) << (8 * 4)) - | ((ptr[5] | zero) << (8 * 5)) - | ((ptr[6] | zero) << (8 * 6)) - | ((ptr[7] | zero) << (8 * 7))); + _GL_STDBIT_UINT_FAST64 + v0 = ptr[0], v1 = ptr[1], v2 = ptr[2], v3 = ptr[3], + v4 = ptr[4], v5 = ptr[5], v6 = ptr[6], v7 = ptr[7]; + return ((v0 << (8 * 0)) | (v1 << (8 * 1)) + | (v2 << (8 * 2)) | (v3 << (8 * 3)) + | (v4 << (8 * 4)) | (v5 << (8 * 5)) + | (v6 << (8 * 6)) | (v7 << (8 * 7))); } _GL_STDC_LOAD8_INLINE int_least8_t -- 2.51.0
