Path: csiph.com!eternal-september.org!feeder.eternal-september.org!nntp.eternal-september.org!eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: _BitInt(N) Date: Mon, 01 Dec 2025 12:34:05 -0800 Organization: None to speak of Lines: 139 Message-ID: <87tsya7xhe.fsf@example.invalid> References: <10dajlh$ko3c$1@dont-email.me> <10g1qq9$2f8lb$4@dont-email.me> <10g28gm$2mf9s$1@dont-email.me> <10g2f2d$2oufq$1@dont-email.me> <10g2m3v$2s5sa$1@dont-email.me> <10gfkqd$19n2d$1@paganini.bofh.team> <10gftqi$3qhkg$1@dont-email.me> <87sedw9wjh.fsf@example.invalid> <10gga8k$3v646$1@dont-email.me> <10gghbg$3htol$4@dont-email.me> <10gheka$bgvr$1@dont-email.me> <10ghu7d$3htol$5@dont-email.me> <10gi0ep$i4fi$1@dont-email.me> <10gima4$1k84u$2@paganini.bofh.team> <10giq57$rn96$1@dont-email.me> <10gj4g5$1q8vh$1@paganini.bofh.team> <10gk9e7$1cggk$2@dont-email.me> MIME-Version: 1.0 Content-Type: text/plain Injection-Date: Mon, 01 Dec 2025 20:34:06 +0000 (UTC) Injection-Info: dont-email.me; posting-host="8213f2dfee378269bbe79a5548f849a1"; logging-data="1754594"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/1iDqf/xSbnJR+0iZ2Jhjr" User-Agent: Gnus/5.13 (Gnus v5.13) Cancel-Lock: sha1:JRdZfbm8LhmZA7UxkTyX4axvhFw= sha1:FVRhB0zpdY70wKrNbzBizZ79rGU= Xref: csiph.com comp.lang.c:395642 bart writes: > On 01/12/2025 04:10, Waldek Hebisch wrote: >> bart wrote: >>> On 01/12/2025 00:08, Waldek Hebisch wrote: >>>> bart wrote: >>>>> >>>>> Yet what I said is pretty much true. Nobody care about BitInt until they >>>>> became aware of, and now it's must-have. They're a must-have if you want a conforming C23 implementation. I don't recall anyone saying they're a "must-have" for any other reason. But if you assert that everyone else things _BitInt types were an absolutely necessary feature to add to the language, it gives you something to argue against. >>>> Well, you were told many times that regulars here know deficiencies >>>> of C. "Nobody care about BitInt" in the sense that before _BitInt >>>> people will say "this can not be expressed directly in C, you need >>>> such and such workaround". People did not loudly complain >>>> knowing that complaints would achive nothing. But say doing >>>> language comparisons they could note that C lack such a feature. >>>> >>>> There is also a psychological phenomenon: computers even in crude >>>> form are quite useful. So people were willing to jump hops to >>>> use them. But when better/easier approach is available people >>>> wery strongly resist going to old ways. So, once w got _BitInt >>>> you will not be able to take it back. >>> >>> I've been claiming that _BitInt was a poor fit for a language at the >>> level of C which lacks some more fundamental features. >>> >>> But I think I was wrong: the way _BitInt has been devised and presented >>> is actually completely in line with the haphazard way C has evolved up >>> to now. >>> >>> I made the mistake in this thread of thinking that people cared about >>> measured language design; obviously if they're using C, they don't. Here you make the mistake of assuming that everyone who disagrees with you doesn't care about language design. You fail to consider the possibility that someone can (a) care about language design *and* (b) be willing to accept the design of C as it is, even with its flaws. >>> unsigned char* p; >>> uint8_t* q; // only exists when stdint.h used >>> unsigned _BitInt(8)* r; >>> char* s; >>> >>> p and q are probably compatible. p and r are not; q and r and not. s is >>> incompatible with p, q, r even if it is unsigned. I've asked you before why it matters to you that some of these types are incompatible. >> Do you understand that uint8_t and _BitInt(8) are different types? > > Well, apparently they aren't. It's not immediately obvious why, but as > I explained above, I realise this is entirely in keeping with how C > works. > >> And the difference is not an accident, but they have different >> properties (uint8_t in expressions promotes to int, _BitInt(8) >> is not subject to this promotion). > > This is another little rule that is not obvious, and out of keeping > with how other types work. Yet add _BitInt(8) to _BitInt(16), and one > side /is/ promoted. And this is all specified in the standard. The *integer promotions* convert a value of any narrow integer type other than a bit-precise type to int or unsigned int; they do not apply to bit-precise types. The *usual arithmetic conversions* resolve the left and right operands of an operator to the same type. The fact that bit-precise integer types are not subject to the integer promotions *is* obvious. It's clearly stated in the C23 standard. > My example was just to highlight the plethora of type denotations that > exist, even for the same machine type. The rules for > type-compatibility and promotions (and the ugly syntax) is just icing > on top. > > This ungainly way to evolve a language is how C works (just look at > all the things wrong with how stdint.h types were handled). > > The following table for example shows the rules for mixed sign > arithmetic: S means the result (32 or 64 bits) has signed type, and u > means it is unsigned: > > u8 u16 u32 u64 i8 i16 i32 i64 > > u8 S S u u S S S S > u16 S S u u S S S S > u32 u u u u u u u S > u64 u u u u u u u u > > i8 S S u u S S S S > i16 S S u u S S S S > i32 S S u u S S S S > i64 S S S u S S S S > > But of course, every C programmer knows this and doesn't need such a chart! I'm not going to take the time to confirm that your chart is correct. It assumes that int is 32 bits; an implementation with 16-bit or 64-bit int would require a different chart. But the fact that you were able to generate the chart means that *you already understand the rules*. You just choose to express those rules in a way that's more confusing. > Here, i8 + u8 gives a signed result; but 'unsigned _BitInt(8 ) + > _Bitint(8)' apparently gives an unsigned result (tested using > _Generic). Yes. That follows from the language rules, and in particular the fact that the new bit-precise types are not subject to the integer promotions. But citing a special case of those rules and taking it out of context just makes the rules seem more confusing -- deliberately, I presume. Am I happy about the C conversion rules? Not entirely. The ANSI C committee had to choose between value-preserving and unsigned-preserving semantics (both choices had been made by existing compilers). I tend to think that unsigned-preserving rules would have been better. And the fact that types narrower than int are promoted before they can be operated on also strikes me as a bit iffy; I think that, for example, having operations on two short int operands yield a short int result would have been cleaner. But I'm far more interested in understanding and explaining the existing rules than in complaining about them. And the rules can't be changed without breaking existing code. > So another plus point for staying close to the C spirit! -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com void Void(void) { Void(); } /* The recursive call of the void */