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, 24 Nov 2025 04:29:19 -0800 Organization: None to speak of Lines: 179 Message-ID: <87ikez4ns0.fsf@example.invalid> References: <10dajlh$ko3c$1@dont-email.me> <10fus62$hl69$1@solani.org> <10fv2dm$3can9$1@paganini.bofh.team> <10fv40v$1f7a2$1@dont-email.me> <87ms4c4bom.fsf@example.invalid> <10g08vm$1us25$1@dont-email.me> MIME-Version: 1.0 Content-Type: text/plain Injection-Date: Mon, 24 Nov 2025 12:29:24 +0000 (UTC) Injection-Info: dont-email.me; posting-host="497198ffef236bf75350d11e6379045b"; logging-data="2535543"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/J/9iLvJBNmI7SOu8eIVrf" User-Agent: Gnus/5.13 (Gnus v5.13) Cancel-Lock: sha1:mUCUGfYjlAI5UE7DPUqpTriMA2o= sha1:s4G+9eVoQHOfdqK2rpthablbB6M= Xref: csiph.com comp.lang.c:395407 bart writes: > On 23/11/2025 22:38, Keith Thompson wrote: >> bart writes: >>> On 23/11/2025 13:32, Waldek Hebisch wrote: >>>> Philipp Klaus Krause wrote: >>>>> Am 22.10.25 um 14:45 schrieb Thiago Adams: >>>>>> Is anyone using or planning to use this new C23 feature? >>>>>> What could be the motivation? >>>>> >>>>> Saving memory by using the smallest multiple-of-8 N that will do. >>>> IIUC nothing in the standard says that it is smallest multiple-of-8. >>>> Using gcc-15.1 on AMD-64 is get 'sizeof(_BitInt(22))' equal to 4, >>>> while the number cound fit in 3 bytes. >>> >>> The rationale mentions a use-case where there is a custom processor >>> that might actually have a 22-bit hardware types. >> What rationale are you referring to? There hasn't been an official >> ISO C Rationale document since C99. > > See Introduction and Rationale here: > > https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2709.pdf Thanks. >>> Implementing such odd-size types on regular 8/16/32/64-bit hardware is >>> full of problems if you want to do it without padding (in order to get >>> the savings). On even with padding (to get the desired overflow >>> semantics). >>> >>> Such as working out how pointers to them will work. >> Why would pointers to _BitInt types be a problem? A _BitInt object >> is a fixed-size chunk of memory, similar to a struct object. > > Saving memory was mentioned. To achieve that means having bitfields > that may not start at bit 0 of a byte, and may cross byte- or > word-boundaries. That part of the rationale appears to be specific to FPGA hardware, not something I know much about. > For example, an array of 1M 5-bit values would occupy 1M 8-bit bytes, > but storing packed values means it would use only 625K bytes. > > Anyway, pointers to individual values, or to some arbitrary element or > slice of such an array, would need some extra info. On the implementations I have access to (gcc and clang), a _BitInt object is an ordinary object, with a size that's whole number of bytes. `unsigned _BitInt(4)`, for example, has 4 value bits and 4 padding bits. (Unless it's a bit-field, but that doesn't give you packed arrays.) I can see the benefit of tightly packing multiple bit-precise integers into an array, but I don't see a way to do that, either with the current gcc and llvm/clang implementations or with the C memory model. >>>>> Also being able to use bit-fields wider than int. >>>> For me main gain is reasonably standard syntax for integers bigger >>>> that 64 bits. >>> >>> Standard syntax I guess would be something like int128_t and >>> int256_t. Such wider integers tend to be powers of two. >>> >>> But there are two problems with _BitInt: >>> >>> * Any odd sizes are allowed, such as _BitInt(391) >> Why is that a problem? If you don't want odd-sized types, don't use >> them. > > It is an unnecessary complication. There will be a lot of extra rules > that maybe partly 'implementation defined', so behaviour may vary. And > people WILL uses those types because they are there, and likely they > will be inefficient. Imposing arbitrary restrictions would introduce more unnecessary complication. As far as I've been able to tell, odd-sized _BitInt types are already implemented (though I've done very little testing). > What happens when a 391-bit type, even unsigned, overflows? These > larger types are likely to use a multiple of 64-bits, and for 391 bits > will need 7 x 64 bits, of which the last word will have 57 bits of > padding. It's very messy. An unsigned _BitInt(391) value wraps around modulo 2**391. In the current gcc and clang implementations, it has a size of 56 bytes, with 391 value bits and 57 value bits. It doesn't seem to be a problem in practice. > Specifying a multiple of 64 bits is better; a power of two even better. Then by all means do so. Operations on _BitInt(448) or _BitInt(512) might even be more efficient than operations on _BitInt(391). If you want the language to restrict allowed widths, how exactly would you specify it? Would you allow 32 but not 33? 64 but not 65? 72? 80? You can impose whatever restrictions you like in your own code. >>> * There appears to be no upper limit on size, so _BitInt(2997901) is a >>> valid type >> The upper limit is specified by the implementation as >> BITINT_MAXWIDTH, a macro defined in . For gcc 15.2.0 on >> x86_64, BITINT_MAXWIDTH is 65535 (2**16-1). For clang 21.1.5 it's >> 8388608 (2**23 bits, 1048576 bytes). clang seems to have some >> problems with _BitInt(8388608). For example, this program: #include >> _BitInt(BITINT_MAXWIDTH) n = 42; >> int main(void) { >> n *= n; >> } >> takes a *long* time to compile with clang. I believe it's generating >> inline code to do the 8388608 by 8388608 bit multiplication. > > Now try it with two disparate sizes. Why? llvm/clang currently has a known problem with multiplication and division on very large _BitInt types. It shouldn't be too difficult for them to correct it. Operations on disparate sizes don't add much complexity (the narrower operand is promoted to the wider type). If you're curious, here's the bug report (I've commented on it), but it's an implementation issue, not a language issue. https://github.com/llvm/llvm-project/issues/126384 >>> So what is the result type of multiplying values of those two types? >> _BitInt types are exempt from the integer promotion rules (so >> _BitInt(3) doesn't promote to int), but the usual arithmetic >> conversions apply. If you multiply values of two _BitInt types, the >> result is the wider of the two types. > > So multiplying even two one-million-bit types could overflow! Of course. These are fixed-width types, not arbitrary precision types. If you want to multiply two _BitInt(1'000'000) values without overflow, you can convert to _BitInt(2'000'000) -- if the compiler supports it. (Don't expect the code to be efficient, at least for now.) > Such limits for /fixed-width/ integers are ridiculous. I acknowledge that you think so. I honestly don't know why the gcc maintainers felt it was worthwhile to support _BitInt types up to 65535 bits, or why the llvm/clang maintainers decided to support up to 8388608 bits. But that's what they've done, and again, you don't have to use it if you don't want to. There could easily be a perfectly valid reason that you and I are not aware of. It's likely that implementing million-bit integers isn't significantly harder than implementing thousand-bit integers. Bit-precise integers up to, say, 128 or 256 bits seem to be implemented reasonably efficiently. How exactly does the fact that compilers support much wider types inconvenience you? > You might say this is no different from defining an array of exactly > 123,456 elements. But the use-cases are very different. > > I starting going into details but I guess you don't care about such > matters or whether the feature makes much sense. On the contrary, I'm curious about it. But if two different compiler teams have already done the work of implementing bit-precise integers with extremely large and/or odd widths, I can think of no reason to complain about it. Even if it doesn't make sense, I didn't have to do the work of implementing it. Incidentally, something odd happens to quoted text in your followups. Blank lines are lost, and paragraphs are reformatted oddly, often with alternating long and short lines. Is your newsreader doing that, or is it something else? Can you do something about it? -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com void Void(void) { Void(); } /* The recursive call of the void */