Path: csiph.com!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: What is your opinion about unsigned int u = -2 ? Date: Fri, 02 Aug 2024 18:25:30 -0700 Organization: None to speak of Lines: 58 Message-ID: <87h6c2fldh.fsf@nosuchdomain.example.com> References: <87bk2cecan.fsf@bsb.me.uk> <87r0b6g3qx.fsf@nosuchdomain.example.com> MIME-Version: 1.0 Content-Type: text/plain Injection-Date: Sat, 03 Aug 2024 03:25:31 +0200 (CEST) Injection-Info: dont-email.me; posting-host="01c35e2bca840e4e4b0a2795d8f6c72e"; logging-data="3248403"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18PaV2TXD/tXBtckRcfDJ1U" User-Agent: Gnus/5.13 (Gnus v5.13) Cancel-Lock: sha1:82PEBe4EpVLy7aJmIRHuP/LOfuU= sha1:hNN6/4n8RORuWRcKAlyYSUGN3WU= Xref: csiph.com comp.lang.c:387282 Thiago Adams writes: [...] > I am doing experiments with constexpr. What happens with overflow in > compile time? The answer is not so clear. Sometimes it does not > compile and sometimes it works as in runtime. Your first example fails due to signed integer overflow. Your second example is well defined because there is no such thing as unsigned integer overflow. > constexpr int i = 1073741823; > constexpr int i2 = i*3/3; /*does not compile*/ The `constexpr` means that the initializer must be a constant expression. `i*3/3` is not a constant expression, because `i*3` is not a constant expression, because its result is not in the range of representable values for its type, violating the constraint in N3220 6.6p4. (Assuming 32-bit int; if int is wider than 32 bits there's no overflow and i2 is 1073741823 .) > But this compiles and outputs > > #include > > int main() > { > constexpr signed char i = -2; > constexpr unsigned long long u = 0ull+i; > printf("%ull", u); /*prints 4294967294*/ > } No, the printf has undefined behavior; it prints "4294967294ll" on my system. The format for unsigned long long is "%llu", not "%ull". You have a "%u" for unsigned int followed by a literal "ll". It's probably printing the low-order 32 bits of the 64-bit value. (You should also have a newline at the end of the output.) Fixing that problem : #include int main() { constexpr signed char i = -2; constexpr unsigned long long u = 0ull+i; printf("%llu\n", u); /*prints 4294967294*/ } The output is "18446744073709551614" (assuming unsigned long long is 64 bits, which it is in every implementation I'm aware of). There's no overflow. `0ull` is of type `unsigned long`, value zero. `i` is of type `signed char`, value -2. For the addition, the usual arithmetic conversions cause the right operand to be converted from signed char to unsigned long long, yielding ULLONG_MAX-2, or 18446744073709551614, or 0xfffffffffffffffe . -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com void Void(void) { Void(); } /* The recursive call of the void */