Path: csiph.com!eternal-september.org!feeder.eternal-september.org!nntp.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c
Subject: Re: this girl calls c ugly
Date: Thu, 04 Jun 2026 03:58:35 -0700
Organization: A noiseless patient Spider
Lines: 80
Message-ID: <861pemd12c.fsf@linuxsc.com>
References: <10v7b32$2u85v$1@dont-email.me> <10vjdn8$22tgu$1@dont-email.me> <10vjp02$6dk$1@reader1.panix.com> <10vjsg2$259m3$3@dont-email.me> <10vkk65$l8v$1@reader1.panix.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Date: Thu, 04 Jun 2026 10:58:36 +0000 (UTC)
Injection-Info: dont-email.me; logging-data="314244"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18JUzB99ovP0TEAW9s5/V1L8YB5Ew1Dj5U="; posting-host="d6853a47af6b5e28b854b4233267d531"
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:36FiygK5jfIwLulKJKVSzNT1zGs= sha1:tknVoS3JH6D6U1yWrysVsOWduS4= sha256:OyNPm2yI8/X4PL3beT2pVmh00Q462pLewzUgMaetuI8= sha1:9HFwS8sECz6M4rv7UhriwseaLJM=
Xref: csiph.com comp.lang.c:399677
cross@spitfire.i.gajendra.net (Dan Cross) writes:
[discussing how to produce a 32-bit color value from rgb16]
> Here's my offering:
>
> // Converts a 16-bit RGB16 (5-6-5) value to an ARGB32
> // ("RGBA8888") value.
> static inline uint32_t
> rgb16_to_argb(uint16_t color)
> {
> const uint32_t blue5 = (color >> 0) & 0x1F;
> const uint32_t green6 = (color >> 5) & 0x3F;
> const uint32_t red5 = (color >> 11) & 0x1F;
>
> // Map from a 5 or 6 bit space into an 8 bit space. A
> // 5-bit number has 32 possibilities; a 6 bit number
> // has 64. We can calculate the projected 8-bit
> // value for a k-bit number v, we can use the formula,
> // v_8 = (v*2^8-1 + (k - 1)/2)/(2^k-1), or
> // (v*255 + 15)/31 (for k=5) or (v*255 + 31)/63 (for
> // k=6.
> //
> // To remove division by a prime and turn it into a
> // shift, the constants below were empirically
> // discovered to generate good results. See
> // https://stackoverflow.com/questions/2442576/
> // how-does-one-convert-16-bit-rgb565-to-24-bit-rgb888
> // for details.
> const uint32_t blue = (blue5 * 527 + 23) >> 6;
> const uint32_t green = (green6 * 259 + 33) >> 6;
> const uint32_t red = (red5 * 527 + 23) >> 6;
> const uint32_t alpha = 0xFF000000;
>
> return blue | (green << 8) | (red << 16) | alpha;
> }
>
> It's longer, yes, but I'd argue it's much easier to understand.
> On my compiler, it generates almost identical code, except that
> some instructions are in a different order.
I would choose a different approach, for two reasons. One is that,
for code that is likely to be in a header file, my preference is
that it be compilable under C90 rules if possible. The other is
that, given the simple nature of the transformation, it should be
able to produce a constant expression if given a constant input
value. Here is an possible implementation:
#define SOLID_RGB24_of_RGB16( rgb16 ) \
ARGB32_( 255ul, \
SCALE_5_to_8_( BITS_AT_OF_( 5, 11, (rgb16) ) ), \
SCALE_6_to_8_( BITS_AT_OF_( 6, 5, (rgb16) ) ), \
SCALE_5_to_8_( BITS_AT_OF_( 5, 0, (rgb16) ) ) \
)
#define ARGB32_( alpha, red, green, blue ) ( \
alpha << 24 | red << 16 | green << 8 | blue \
)
#define SCALE_5_to_8_( u ) ( u *527ul +23 >>6 )
#define SCALE_6_to_8_( u ) ( u *259ul +33 >>6 )
#define BITS_AT_OF_(width,where,u) ( u >> where & (1ul << width)-1 )
And here is a simple test driver:
const unsigned long some_red = SOLID_RGB24_of_RGB16( 29u << 11 );
const unsigned long some_green = SOLID_RGB24_of_RGB16( 59u << 5 );
const unsigned long some_blue = SOLID_RGB24_of_RGB16( 29u << 0 );
#include
int
main(){
printf( " red: %#8lx\n", some_red );
printf( " green: %#8lx\n", some_green );
printf( " blue: %#8lx\n", some_blue );
}