Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #399456 > unrolled thread
| Started by | fir <profesor.fir@gmail.com> |
|---|---|
| First post | 2026-05-27 19:53 +0200 |
| Last post | 2026-05-30 11:18 +0200 |
| Articles | 20 on this page of 276 — 21 participants |
Back to article view | Back to comp.lang.c
this girl calls c ugly fir <profesor.fir@gmail.com> - 2026-05-27 19:53 +0200
Re: this girl calls c ugly fir <profesor.fir@gmail.com> - 2026-05-27 20:15 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-27 18:49 -0500
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-28 04:53 +0000
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-28 02:35 -0500
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-28 23:32 +0000
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-28 20:07 -0500
Re: this girl calls c ugly Bonita Montero <Bonita.Montero@gmail.com> - 2026-05-28 11:48 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-28 09:18 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-28 04:57 -0500
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-28 23:35 +0000
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 09:52 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-29 05:20 -0500
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-29 13:22 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-29 15:16 -0500
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-30 13:52 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-30 14:40 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-30 16:36 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-30 15:48 -0500
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 11:14 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-31 13:25 -0500
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 22:14 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 15:22 +0200
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-30 03:49 +0000
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-05-28 12:47 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 09:56 +0200
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-05-29 11:00 -0700
Re: this girl calls c ugly fir <profesor.fir@gmail.com> - 2026-05-28 17:12 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-28 14:07 -0500
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-28 23:54 +0000
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 10:02 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 12:19 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 14:46 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 14:22 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 17:15 +0200
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-05-29 15:59 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 17:12 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 18:48 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 19:09 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 22:00 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 22:14 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-29 12:09 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 17:05 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 18:34 +0200
Re: this girl calls c ugly tTh <tth@none.invalid> - 2026-05-29 19:29 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 18:53 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-29 12:28 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 20:49 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 22:03 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-29 13:56 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 22:54 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-29 15:52 -0700
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-29 20:31 -0400
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-30 02:03 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-29 19:02 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-30 12:12 +0100
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-05-30 12:29 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-30 13:56 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-30 16:43 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-31 03:37 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-30 19:53 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 12:16 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 11:47 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 12:55 +0200
Re: this girl calls c ugly Richard Harnden <richard.nospam@gmail.invalid> - 2026-05-31 09:12 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 11:49 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-31 11:10 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 13:18 +0200
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-31 10:24 -0400
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 17:35 +0200
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-31 12:46 -0400
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 22:24 +0200
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-31 18:26 -0400
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 08:28 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-31 15:54 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 08:39 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 02:33 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 11:48 +0200
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-06-02 06:37 -0400
Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-02 05:06 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 16:28 +0000
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-04 03:37 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 16:31 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 13:36 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 23:49 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 18:04 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-06 03:10 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 23:50 -0700
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-06 15:47 -0700
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-06 16:36 -0700
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-06 16:43 -0700
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-06 17:41 -0700
Re: Constants and undefined behavior Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-05 10:41 +0200
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 10:49 -0700
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-06 16:15 -0700
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-06 18:06 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 05:35 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-02 06:29 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 16:10 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 15:29 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-05 06:41 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 11:24 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-06 03:22 +0000
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 23:56 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-07 13:37 +0000
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-06-02 13:59 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 13:05 +0000
Parentheses (was: this girl calls c ugly) Bart <bc@freeuk.com> - 2026-06-02 14:38 +0100
Re: Parentheses (was: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 15:19 +0000
Re: Parentheses antispam@fricas.org (Waldek Hebisch) - 2026-06-03 22:30 +0000
Re: Parentheses Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-03 16:24 -0700
Re: Parentheses antispam@fricas.org (Waldek Hebisch) - 2026-06-04 02:03 +0000
Re: Parentheses Bart <bc@freeuk.com> - 2026-06-04 01:12 +0100
Re: Parentheses antispam@fricas.org (Waldek Hebisch) - 2026-06-04 01:58 +0000
Re: Parentheses Bart <bc@freeuk.com> - 2026-06-04 11:37 +0100
Re: Parentheses cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 10:51 +0000
Re: Parentheses Bart <bc@freeuk.com> - 2026-06-04 12:47 +0100
Re: Parentheses Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 14:57 +0200
Re: Parentheses cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 14:31 +0000
[OT] Fancy graphics (was Re: this girl calls c ugly) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 15:54 +0200
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) Bart <bc@freeuk.com> - 2026-06-02 15:19 +0100
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 15:19 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 17:39 +0200
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 16:36 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) scott@slp53.sl.home (Scott Lurndal) - 2026-06-02 21:33 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-06-02 14:43 -0700
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) ram@zedat.fu-berlin.de (Stefan Ram) - 2026-06-02 17:08 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 19:19 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-06-04 00:11 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 15:39 -0700
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-03 13:14 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-02 15:10 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 15:31 +0000
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-31 10:15 -0400
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 16:29 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-31 03:45 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-31 04:02 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-31 09:04 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-31 18:11 +0100
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-05-31 19:34 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-31 19:10 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-01 11:12 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 12:36 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 14:26 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-04 02:34 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 12:40 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-04 14:35 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 14:18 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 15:47 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 15:57 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-04 16:27 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 16:46 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 20:15 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-04 20:54 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 20:29 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 14:06 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 22:47 +0100
Famous (hopefully last) words [on this topic] Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-05 00:27 +0200
Re: Famous (hopefully last) words [on this topic] Bad Post <invalid@invalid.invalid> - 2026-06-05 01:20 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 16:09 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-05 00:44 +0100
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-06-04 17:26 -0700
Re: this girl calls c ugly antispam@fricas.org (Waldek Hebisch) - 2026-06-05 12:58 +0000
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-06-05 14:27 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 02:47 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-05 00:53 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-05 11:04 +0100
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-05 05:34 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-06 03:45 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-06 03:44 +0000
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-06 07:39 +0200
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-06-04 15:25 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-05 09:29 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-05 12:39 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-05 15:42 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-05 16:50 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 11:09 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-05 20:29 +0100
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 16:18 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 17:23 +0100
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 16:47 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 19:57 +0100
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 20:34 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 22:28 +0100
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 21:58 +0000
Re: this girl calls c ugly Richard Harnden <richard.nospam@gmail.invalid> - 2026-06-04 23:25 +0100
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 02:49 +0000
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 19:47 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-04 21:04 +0200
Re: this girl calls c ugly Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2026-06-04 19:13 +0000
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-05 10:34 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 12:11 -0700
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-06-04 16:33 -0400
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 14:16 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 00:02 +0000
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 18:36 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 02:54 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-05 05:49 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 11:01 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-05 11:53 -0700
Re: this girl calls c ugly Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2026-06-04 18:45 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 20:19 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 20:31 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 20:41 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 20:49 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 00:03 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-05 00:18 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 03:02 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-05 14:04 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-06 03:49 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-06 15:13 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-06 17:53 +0000
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 11:59 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 15:21 +0200
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-04 06:38 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 09:52 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 02:42 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 12:50 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-01 11:47 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 12:55 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 14:39 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 15:11 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 08:41 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 02:07 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 11:38 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 05:01 -0700
It is not futile to change the subject line (Was: this girl calls c ugly) gazelle@shell.xmission.com (Kenny McCormack) - 2026-06-02 12:39 +0000
Re: It is not futile to change the subject line (Was: this girl calls c ugly) gazelle@shell.xmission.com (Kenny McCormack) - 2026-06-02 12:42 +0000
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 11:46 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-02 11:09 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 05:25 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-02 14:20 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 15:12 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-02 04:16 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-01 15:23 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 16:06 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-01 23:24 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 11:35 +0200
Operator precedence in other (non-C, but "C-like") languages (Was: something about a girl) gazelle@shell.xmission.com (Kenny McCormack) - 2026-06-02 12:36 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-01 11:04 +0000
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 14:04 +0200
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-01 18:48 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-01 21:04 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 09:17 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 09:09 +0200
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 12:07 +0000
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 14:37 +0200
Microcontroller software stacks (was Re: this girl calls c ugly) scott@slp53.sl.home (Scott Lurndal) - 2026-06-02 15:06 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-04 03:58 -0700
Re: this girl calls c ugly dave_thompson_2@comcast.net - 2026-06-06 19:02 -0400
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-05-31 19:11 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-31 16:08 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-31 16:32 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-31 17:12 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-30 14:07 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 18:10 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 19:18 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 22:17 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 21:47 +0100
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-29 15:57 -0400
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 22:34 +0200
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-29 23:18 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-30 01:26 +0100
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-30 04:25 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-30 12:01 +0100
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-31 00:29 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-31 10:59 +0100
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-06-01 00:33 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-01 02:26 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 13:24 +0200
Re: this girl calls c ugly Bonita Montero <Bonita.Montero@gmail.com> - 2026-05-29 08:09 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-29 04:15 -0500
Re: this girl calls c ugly Bonita Montero <Bonita.Montero@gmail.com> - 2026-05-29 14:58 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-30 01:04 -0500
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-29 23:20 +0000
Re: this girl calls c ugly Bonita Montero <Bonita.Montero@gmail.com> - 2026-05-30 11:18 +0200
Page 5 of 14 — ← Prev page 1 … 3 4 [5] 6 7 … 14 Next page →
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-02 16:28 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vn0bk$ghg$1@reader1.panix.com> |
| In reply to | #399615 |
In article <86ik81cfk5.fsf_-_@linuxsc.com>,
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
>
>> On 2026-06-01 00:54, Keith Thompson wrote:
>>
>>>> [...]
>>>
>>> Yes, a compiler can reduce (a + b) * 0 to just 0. But it's not
>>> required to do so, and (INT_MAX + 1) * 0 still has undefined
>>> behavior. Undefined behavior is determined by the rules of the
>>> abstract machine *without* any adjustments permitted by the as-if
>>> rule.
>>
>> This is something I really don't get in the actual C-logic...
>>
>> Using constants that can be determined at compile time is UB here,
>> despite the '* 0' mathematically indicating an IMO clear semantics,
>> but using variables is only UB possibly at runtime? [...]
>
>There's an important distinction to make here. Consider this
>program:
>
> #include <limits.h>
>
> int
> foo(){
> int zero = (INT_MAX+1)*0;
> return zero;
> }
>
> int
> main(){
> return 0;
> }
>
>This program does not transgress the bounds of undefined behavior.
Given that `foo` has external linkage, I find this hard to
believe, and `clang -fsanitize=undefined` agrees with me,
both emitting a diagnostic about the overflow and generating
code in `foo` to call into the sanitizer machinery.
Perhaps you mean that this is irrelevant because `foo` is not
invoked, but I see no reason why that need be the case in e.g.
a freestanding environment. In a hosted environment, I don't
think anything explicitly prevents `foo` from being called after
`main` returns (though I can't imagine that would happen in real
life; it would be weird if it did).
But I'm not sure what _you_ mean by "transgress the bounds of
undefined behavior" here.
>Even more than that, the program is strictly conforming, and must be
>accepted by a conforming implementation.
See above.
>Now let's change the program slightly:
>
> #include <limits.h>
>
> int
> foo(){
> static int zero = (INT_MAX+1)*0;
> return zero;
> }
>
> int
> main(){
> return 0;
> }
>
>This program does transgress the bounds of undefined behavior. The
>reason for the difference is that in the first program the semantics
>of foo() is to evaluate the expression to be stored in 'zero' only
>at runtime, whereas in the second program the semantics of foo() is
>to evaluate the expression to be stored in 'zero' before program
>startup (informally, "at compile time"). What matters is not
>whether the offending expression /might/ be evaluated "at compile
>time", but whether the offending expression /must/ be evaluated "at
>compile time". Only in the second case is undefined behavior
>inevitable (and thus it does not occur in the first program).
>
>Fine point: strictly speaking, I believe the C standard allows even
>the second program to complete translation phase 8 successfully, and
>for any offending behavior to occur only when we actually try to run
>the program. To say that another way, there is no requirement that
>possible nasal demons be made manifest at any point before an actual
>attempted execution. On the other hand, because that possibility is
>there lurking in the background, there is no requirement that the
>program be accepted, and could be rejected by a conforming compiler.
Indeed. Further, I believe that the same is true for the first
program, as well.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2026-06-04 03:37 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <865x3yd21n.fsf@linuxsc.com> |
| In reply to | #399636 |
cross@spitfire.i.gajendra.net (Dan Cross) writes:
> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>
>> Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
>>
>>> On 2026-06-01 00:54, Keith Thompson wrote:
>>>
>>>>> [...]
>>>>
>>>> Yes, a compiler can reduce (a + b) * 0 to just 0. But it's not
>>>> required to do so, and (INT_MAX + 1) * 0 still has undefined
>>>> behavior. Undefined behavior is determined by the rules of the
>>>> abstract machine *without* any adjustments permitted by the as-if
>>>> rule.
>>>
>>> This is something I really don't get in the actual C-logic...
>>>
>>> Using constants that can be determined at compile time is UB here,
>>> despite the '* 0' mathematically indicating an IMO clear semantics,
>>> but using variables is only UB possibly at runtime? [...]
>>
>> There's an important distinction to make here. Consider this
>> program:
>>
>> #include <limits.h>
>>
>> int
>> foo(){
>> int zero = (INT_MAX+1)*0;
>> return zero;
>> }
>>
>> int
>> main(){
>> return 0;
>> }
>>
>> This program does not transgress the bounds of undefined behavior.
To clarify, the comments in my posting were meant to be read as
saying the given text is the entire program, and that it is strictly
conforming with respect to conforming hosted implementations.
(Incidentally, given the rules for freestanding implementations, I'm
not sure that it is even possible for any program to be strictly
conforming with respect to conforming freestanding implementations.
In any case my statements were meant only in the context of hosted
implementations.)
> Given that `foo` has external linkage, I find this hard to
> believe, and `clang -fsanitize=undefined` agrees with me,
> both emitting a diagnostic about the overflow and generating
> code in `foo` to call into the sanitizer machinery.
A conforming implementation is free to emit a diagnostic whenever it
chooses, for any reason at all, regardless of whether the program
source is legal C or not. (I feel obliged to point out that, if a
preprocessing #error directive is encountered, then there may be an
exception to that statement; however, there is no such #error in
the program shown above.)
> Perhaps you mean that this is irrelevant because `foo` is not
> invoked, but I see no reason why that need be the case in e.g.
> a freestanding environment.
I explained the context of my previous statements above. Sorry for
not saying that in the original message.
> In a hosted environment, I don't
> think anything explicitly prevents `foo` from being called after
> `main` returns (though I can't imagine that would happen in real
> life; it would be weird if it did).
The semantics described in the ISO C standard don't admit that
possibility. Whether foo() has external linkage or internal
linkage doesn't change that. Only those actions initiated by
statements in main() are ever elaborated.
> But I'm not sure what _you_ mean by "transgress the bounds of
> undefined behavior" here.
It's a grammatical fine point. I think for present purposes it's
okay to gloss over the distinction, and say this statement may be
read as saying "the program does not have undefined behavior".
>> Even more than that, the program is strictly conforming, and must be
>> accepted by a conforming implementation.
>
> See above.
>
>> Now let's change the program slightly:
>>
>> #include <limits.h>
>>
>> int
>> foo(){
>> static int zero = (INT_MAX+1)*0;
>> return zero;
>> }
>>
>> int
>> main(){
>> return 0;
>> }
>>
>> This program does transgress the bounds of undefined behavior. The
>> reason for the difference is that in the first program the semantics
>> of foo() is to evaluate the expression to be stored in 'zero' only
>> at runtime, whereas in the second program the semantics of foo() is
>> to evaluate the expression to be stored in 'zero' before program
>> startup (informally, "at compile time"). What matters is not
>> whether the offending expression /might/ be evaluated "at compile
>> time", but whether the offending expression /must/ be evaluated "at
>> compile time". Only in the second case is undefined behavior
>> inevitable (and thus it does not occur in the first program).
>>
>> Fine point: strictly speaking, I believe the C standard allows even
>> the second program to complete translation phase 8 successfully, and
>> for any offending behavior to occur only when we actually try to run
>> the program. To say that another way, there is no requirement that
>> possible nasal demons be made manifest at any point before an actual
>> attempted execution. On the other hand, because that possibility is
>> there lurking in the background, there is no requirement that the
>> program be accepted, and could be rejected by a conforming compiler.
>
> Indeed. Further, I believe that the same is true for the first
> program, as well.
It isn't. In the first program the offending expression is never
evaluated, because foo() is never called.
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-04 16:31 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vs997$rp5$1@reader1.panix.com> |
| In reply to | #399674 |
In article <865x3yd21n.fsf@linuxsc.com>,
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>> Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
>>>> On 2026-06-01 00:54, Keith Thompson wrote:
>>>>>> [...]
>>>>>
>>>>> Yes, a compiler can reduce (a + b) * 0 to just 0. But it's not
>>>>> required to do so, and (INT_MAX + 1) * 0 still has undefined
>>>>> behavior. Undefined behavior is determined by the rules of the
>>>>> abstract machine *without* any adjustments permitted by the as-if
>>>>> rule.
>>>>
>>>> This is something I really don't get in the actual C-logic...
>>>>
>>>> Using constants that can be determined at compile time is UB here,
>>>> despite the '* 0' mathematically indicating an IMO clear semantics,
>>>> but using variables is only UB possibly at runtime? [...]
>>>
>>> There's an important distinction to make here. Consider this
>>> program:
>>>
>>> #include <limits.h>
>>>
>>> int
>>> foo(){
>>> int zero = (INT_MAX+1)*0;
>>> return zero;
>>> }
>>>
>>> int
>>> main(){
>>> return 0;
>>> }
>>>
>>> This program does not transgress the bounds of undefined behavior.
>
>To clarify, the comments in my posting were meant to be read as
>saying the given text is the entire program, and that it is strictly
>conforming with respect to conforming hosted implementations.
>(Incidentally, given the rules for freestanding implementations, I'm
>not sure that it is even possible for any program to be strictly
>conforming with respect to conforming freestanding implementations.
>In any case my statements were meant only in the context of hosted
>implementations.)
Ok.
>> [snip]
>> Perhaps you mean that this is irrelevant because `foo` is not
>> invoked, but I see no reason why that need be the case in e.g.
>> a freestanding environment.
>
>I explained the context of my previous statements above. Sorry for
>not saying that in the original message.
>
>> In a hosted environment, I don't
>> think anything explicitly prevents `foo` from being called after
>> `main` returns (though I can't imagine that would happen in real
>> life; it would be weird if it did).
>
>The semantics described in the ISO C standard don't admit that
>possibility.
Could you please point to where it says this, in the C standard?
I cannot find anything that says that arbitrary code cannot run
after `main()` returns, and I don't see how that could possibly
be true.
>Whether foo() has external linkage or internal
>linkage doesn't change that.
I disagree. There's no possible way for the implementation to
know whether a function with external linkage will be ultimately
invoked or not; consider a system that supports loadable shared
modules. Nothing prevents even this simple program from being
compiled as a shared module, dynamically loaded, the loading
program explicitly searching for and finding the symbol
corresponding to the `foo` function, and invoking it.
Hence, the compiler _must_ treat with UB as written, which is
why `ubsan` inserts trapping code in `foo`.
In your example, `foo` clearly exhibits UB; I think your
argument is whether that has a realized effect or not, since the
UB is not invoked. I'm saying that in general a compiler cannot
possibly know that when it compiles `foo`, and is free to assume
the worst.
>Only those actions initiated by
>statements in main() are ever elaborated.
This is not true: code can obviously run outside of the bounds
of `main`, for several reasons.
First, there is the issue of static initializers, which you had
mentioned earlier. Not at play here, but it does invalidate
your statement above, as these run "before" main is invoked.
Second, we know that code can run after because `atexit` can be
used to register handlers that will run after it terminates: as
section 5.1.2.3.4 of n3220 says, "a return from the initial call
to the main function is equivalent to calling the exit function
with the value returned by the main function as its argument",
which means that it will run `atexit` handlers. (But, as the
footnote warns, lifetimes of variables with automatic storage
duration have ended in this case in accordance with sec 6.2.4,
since `main` has terminated.)
Third, it is possible to invoke code that may conditionally be
executed, such as signal handlers, in response to external
events. Certainly, `signal(SIGINT, some_handler);` does not
immediately guarantee that `some_handler` is run, but it does
not prevent it from running, either.
Of course, for the second and third points, we must acknowledge
that one might quibble about what it means to say that a program
invokes "actions initiated by statements in main()".
Registering signal and exit handlers is (generally) going to be
something done in as the consequence of an "action initiated by
statements in main()". And subsequent invocation of (say)
`some_handler` in the example above in response to receipt of a
`SIGINT` signal is arguably a consequence of that.
>> But I'm not sure what _you_ mean by "transgress the bounds of
>> undefined behavior" here.
>
>It's a grammatical fine point. I think for present purposes it's
>okay to gloss over the distinction, and say this statement may be
>read as saying "the program does not have undefined behavior".
Except it does. `foo` is an example of what Regehr calls a
"Type 3" function in https://blog.regehr.org/archives/213.
Also you are discounting time-travel; code not not actually
invoke UB to suffer from it. The mere existence of it can be
enough.
https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633
Moreover, undefined behavior simply is; the definition from the
C standard does not say that time-traveling "post-modern"
compilers are free to assume and do anything if they observe UB
anywhere in a program.
Here, because `foo` has external linkage, the compiler cannot
know whether `foo` is invoked or not, and I see nothing
preventing it from assuming that the entire program is in error.
In particular, I don't think there is anything that prevents a
compiler from simply emitting `int main(void) { abort(); }`.
>>> Even more than that, the program is strictly conforming, and must be
>>> accepted by a conforming implementation.
>>
>> See above.
>>
>>> Now let's change the program slightly:
>>>
>>> #include <limits.h>
>>>
>>> int
>>> foo(){
>>> static int zero = (INT_MAX+1)*0;
>>> return zero;
>>> }
>>>
>>> int
>>> main(){
>>> return 0;
>>> }
>>>
>>> This program does transgress the bounds of undefined behavior. The
>>> reason for the difference is that in the first program the semantics
>>> of foo() is to evaluate the expression to be stored in 'zero' only
>>> at runtime, whereas in the second program the semantics of foo() is
>>> to evaluate the expression to be stored in 'zero' before program
>>> startup (informally, "at compile time"). What matters is not
>>> whether the offending expression /might/ be evaluated "at compile
>>> time", but whether the offending expression /must/ be evaluated "at
>>> compile time". Only in the second case is undefined behavior
>>> inevitable (and thus it does not occur in the first program).
>>>
>>> Fine point: strictly speaking, I believe the C standard allows even
>>> the second program to complete translation phase 8 successfully, and
>>> for any offending behavior to occur only when we actually try to run
>>> the program. To say that another way, there is no requirement that
>>> possible nasal demons be made manifest at any point before an actual
>>> attempted execution. On the other hand, because that possibility is
>>> there lurking in the background, there is no requirement that the
>>> program be accepted, and could be rejected by a conforming compiler.
>>
>> Indeed. Further, I believe that the same is true for the first
>> program, as well.
>
>It isn't. In the first program the offending expression is never
>evaluated, because foo() is never called.
See above.
Of course, I don't think any of this would _actually_ happen,
and if it did, one should take the compiler that does it and
toss it in the trash. But I don't think it's prohibited,
either; such is one of the consequences of an informal
specification like the C standard. Time-travel is especially
pernicious in post-modern compilers.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-04 13:36 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vsnl7$lkmu$1@kst.eternal-september.org> |
| In reply to | #399693 |
cross@spitfire.i.gajendra.net (Dan Cross) writes:
> In article <865x3yd21n.fsf@linuxsc.com>,
> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
[...]
>>>> There's an important distinction to make here. Consider this
>>>> program:
>>>>
>>>> #include <limits.h>
>>>>
>>>> int
>>>> foo(){
>>>> int zero = (INT_MAX+1)*0;
>>>> return zero;
>>>> }
>>>>
>>>> int
>>>> main(){
>>>> return 0;
>>>> }
>>>>
>>>> This program does not transgress the bounds of undefined behavior.
>>
>>To clarify, the comments in my posting were meant to be read as
>>saying the given text is the entire program, and that it is strictly
>>conforming with respect to conforming hosted implementations.
>>(Incidentally, given the rules for freestanding implementations, I'm
>>not sure that it is even possible for any program to be strictly
>>conforming with respect to conforming freestanding implementations.
>>In any case my statements were meant only in the context of hosted
>>implementations.)
>
> Ok.
>
>>> [snip]
>>> Perhaps you mean that this is irrelevant because `foo` is not
>>> invoked, but I see no reason why that need be the case in e.g.
>>> a freestanding environment.
>>
>>I explained the context of my previous statements above. Sorry for
>>not saying that in the original message.
>>
>>> In a hosted environment, I don't
>>> think anything explicitly prevents `foo` from being called after
>>> `main` returns (though I can't imagine that would happen in real
>>> life; it would be weird if it did).
>>
>>The semantics described in the ISO C standard don't admit that
>>possibility.
>
> Could you please point to where it says this, in the C standard?
>
> I cannot find anything that says that arbitrary code cannot run
> after `main()` returns, and I don't see how that could possibly
> be true.
N3220 5.1.2.4, Program semantics.
It defines the *observable behavior* of a program, which consists of
accesses to volatile objects, data written to files, and I/O dynamics of
interactive devices.
If the usual "Hello, world" program prints "Hello, world" followed
by "Goodbye", the implementation is non-conforming. If it formats
my hard drive after printing "Goodbye", it's non-conforming and
dangerous.
>>Whether foo() has external linkage or internal
>>linkage doesn't change that.
>
> I disagree. There's no possible way for the implementation to
> know whether a function with external linkage will be ultimately
> invoked or not; consider a system that supports loadable shared
> modules. Nothing prevents even this simple program from being
> compiled as a shared module, dynamically loaded, the loading
> program explicitly searching for and finding the symbol
> corresponding to the `foo` function, and invoking it.
Remember that linking is translation phase 8. The compiler is not
the entire implementation.
> Hence, the compiler _must_ treat with UB as written, which is
> why `ubsan` inserts trapping code in `foo`.
I don't know what "_must_ treat with UB" means.
foo() has undefined behavior if it's called, so replacing its
body with trapping code is valid. But (I'm reasonably sure that)
an implementation cannot reject a program just because it can't
prove that it has no undefined behavior during execution. It can
reject it if it can prove that it *always* has undefined behavior
during execution.
> In your example, `foo` clearly exhibits UB; I think your
> argument is whether that has a realized effect or not, since the
> UB is not invoked. I'm saying that in general a compiler cannot
> possibly know that when it compiles `foo`, and is free to assume
> the worst.
foo() exhibits UB if and only if it's called during execution.
Yes, a compiler can't know whether foo() will be called.
An implementation, particularly a linker, might know, but is not
required to. No, it is not free to assume the worst.
I certainly wouldn't want a compiler to reject `1/time(NULL)`
because it can't prove that time(NULL) won't be zero, or reject
`argc+1` because it can't prove that argc < INT_MAX. Code whose
behavior would be undefined if it were executed has no behavior
(and therefore no UB) if it's not executed.
[...]
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-04 23:49 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vt2un$fuu$1@reader1.panix.com> |
| In reply to | #399710 |
In article <10vsnl7$lkmu$1@kst.eternal-september.org>,
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>> In article <865x3yd21n.fsf@linuxsc.com>,
>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>[...]
>>>>> There's an important distinction to make here. Consider this
>>>>> program:
>>>>>
>>>>> #include <limits.h>
>>>>>
>>>>> int
>>>>> foo(){
>>>>> int zero = (INT_MAX+1)*0;
>>>>> return zero;
>>>>> }
>>>>>
>>>>> int
>>>>> main(){
>>>>> return 0;
>>>>> }
>>>>>
>>>>> This program does not transgress the bounds of undefined behavior.
>>>
>>>To clarify, the comments in my posting were meant to be read as
>>>saying the given text is the entire program, and that it is strictly
>>>conforming with respect to conforming hosted implementations.
>>>(Incidentally, given the rules for freestanding implementations, I'm
>>>not sure that it is even possible for any program to be strictly
>>>conforming with respect to conforming freestanding implementations.
>>>In any case my statements were meant only in the context of hosted
>>>implementations.)
>>
>> Ok.
>>
>>>> [snip]
>>>> Perhaps you mean that this is irrelevant because `foo` is not
>>>> invoked, but I see no reason why that need be the case in e.g.
>>>> a freestanding environment.
>>>
>>>I explained the context of my previous statements above. Sorry for
>>>not saying that in the original message.
>>>
>>>> In a hosted environment, I don't
>>>> think anything explicitly prevents `foo` from being called after
>>>> `main` returns (though I can't imagine that would happen in real
>>>> life; it would be weird if it did).
>>>
>>>The semantics described in the ISO C standard don't admit that
>>>possibility.
>>
>> Could you please point to where it says this, in the C standard?
>>
>> I cannot find anything that says that arbitrary code cannot run
>> after `main()` returns, and I don't see how that could possibly
>> be true.
>
>N3220 5.1.2.4, Program semantics.
>
>It defines the *observable behavior* of a program, which consists of
>accesses to volatile objects, data written to files, and I/O dynamics of
>interactive devices.
Yes, but it does so for strictly-conforming programs with no UB.
To understand conformance, we have to jump over to section 4,
which explicitly says that, 'Undefined behavior is otherwise
indicated in this document by the words "undefined behavior" or
by the omission of any explicit definition of behavior.' As it
does not say that a program with an instance of undefined
behavior in an integer constant expression that is not executed
must otherwise behave in any given manner, what the program does
is undefined. A constaint violation mandates a diagnostic, but
beyond that, the standard is (AFAICT) silent.
Undefined Behavior, in turn, is not defined as specific only to
execution: the standard simply says that it is "behavior, upon
use of a *nonportable or erroneous program construct*..." for
which there are no requirements, and there are examples of
things that are explicitly UB at translation time, such as
improperly terminated lexemes and so forth.
Furthermore, the expression above is obviously an integer
constant expression as defined by sec 6.6 para 8. Section 6.6,
para 4, reads in part, "Each constant expression shall evaluate
to a constant that is in the range of representable values for
its type." The expression, `(INT_MAX+1)*0` violates this
constraint, and so therefore a diagnostic is mandated as per
sec 5.1.1.3 para 1. That it appears in code that is not
obviously called from `main` doesn't change that.
Morever, sec 6.6 para 17 says that, "the semantic rules for
evaluation of a constant expression are the same as for
nonconstant expressions." This brings us back to 5.1.2.4,
though I submit that para (4) is a stronger argument for what
you and Tim are saying, as it reads in part, "An actual
implementation is not required to evaluate part of an expression
if it can deduce that its value is not used and that no needed
side effects are produced (including any caused by calling a
function or through volatile access to an object)." I interpret
this to mean that, if the implementation can determine that
there is no way that `foo` can be called, it does not _have_ to
evaluate the above expression. However, it must satisfy the
range constraint from section 6.6, so it likely will, and in any
event, the standard does not say that it, "shall not" evaluate
it, or when.
Once the compiler does that, if it does, and observes UB, the
standard is silent on what requirements it imposes, which means
the behavior is undefined. I see no reason it couldn't arrange
to invoke `foo` at that point.
So no, I do not see how execution according to the rules of the
abstract machine is not guaranteed, here. I certainly see no
way in which this can be regarded as a strictly conforming
program.
>If the usual "Hello, world" program prints "Hello, world" followed
>by "Goodbye", the implementation is non-conforming. If it formats
>my hard drive after printing "Goodbye", it's non-conforming and
>dangerous.
Two separate things. My point earlier was that code can
obviously run after `main` terminates. Moreoever, I can't
imagine what would _prevent_ a runtime system that invokes
`main` from doing something like printing, "PROGRAM STOPPED"
after `main` returned. C imposes no requirements here.
Whether `foo` could be invoked after, I think, is undefined.
>>>Whether foo() has external linkage or internal
>>>linkage doesn't change that.
>>
>> I disagree. There's no possible way for the implementation to
>> know whether a function with external linkage will be ultimately
>> invoked or not; consider a system that supports loadable shared
>> modules. Nothing prevents even this simple program from being
>> compiled as a shared module, dynamically loaded, the loading
>> program explicitly searching for and finding the symbol
>> corresponding to the `foo` function, and invoking it.
>
>Remember that linking is translation phase 8. The compiler is not
>the entire implementation.
Exactly my point. The compiler cannot know how `foo` might be
used, or how the translated object might be exercised. There's
I don't see how it could possibly know that, given that `foo`
has external linkage.
>> Hence, the compiler _must_ treat with UB as written, which is
>> why `ubsan` inserts trapping code in `foo`.
>
>I don't know what "_must_ treat with UB" means.
>
>foo() has undefined behavior if it's called, so replacing its
>body with trapping code is valid. But (I'm reasonably sure that)
>an implementation cannot reject a program just because it can't
>prove that it has no undefined behavior during execution. It can
>reject it if it can prove that it *always* has undefined behavior
>during execution.
What I'm saying is that, `foo` has undefined behavior _period_.
That's manifest in an integer constant expression, whether it is
executed at runtime or not. I believe that the standard forces
the expression to be evaluated at translation time, via the
"shall" mandate when checking the constraint on the range in sec
6.6 para 4. Further, that evaluation must happen in accordance
with the rules of the abstract machine, as per 5.1.2.4 para 17.
The diagnostic is mandated, as is the translation-time
evaluation. The expression is itself manifestly exhibits UB,
and so therefore the result of the rest of the translation is
undefined.
I could be wrong; this is all excessively pedantic. And of
course, if an implementation does something silly and emits
garbage for Tim's program, then I argue it should be chucked
onto the dustbin of excessive fawning over the standard. But
I'm not convinced that the standard _prohibits_ such an extreme
interpretation.
>> In your example, `foo` clearly exhibits UB; I think your
>> argument is whether that has a realized effect or not, since the
>> UB is not invoked. I'm saying that in general a compiler cannot
>> possibly know that when it compiles `foo`, and is free to assume
>> the worst.
>
>foo() exhibits UB if and only if it's called during execution.
>
>Yes, a compiler can't know whether foo() will be called.
>An implementation, particularly a linker, might know, but is not
>required to. No, it is not free to assume the worst.
See above.
>I certainly wouldn't want a compiler to reject `1/time(NULL)`
>because it can't prove that time(NULL) won't be zero, or reject
>`argc+1` because it can't prove that argc < INT_MAX. Code whose
>behavior would be undefined if it were executed has no behavior
>(and therefore no UB) if it's not executed.
That's categorically different; what you are describing are what
Regehr calls, "Type-2" functions, and I agree with you for
those.
The program that Tim posted has a "Type-3" function, and
constraints dictate that the UB express must be evaluated at
translation time, and a diagnostic emitted. In the most
charitable interpretation, it cannot be considered a strictly
conforming program, even if the implementation is smart enough
to avoid evaluating the constant expression, as it is
unspecified whether it's evaluated or not, and strictly
conforming programs shall not rely on unspecified behavior.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-04 18:04 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vt7b9$pi3s$1@kst.eternal-september.org> |
| In reply to | #399725 |
cross@spitfire.i.gajendra.net (Dan Cross) writes:
> In article <10vsnl7$lkmu$1@kst.eternal-september.org>,
> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>> In article <865x3yd21n.fsf@linuxsc.com>,
>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>[...]
>>>>>> There's an important distinction to make here. Consider this
>>>>>> program:
>>>>>>
>>>>>> #include <limits.h>
>>>>>>
>>>>>> int
>>>>>> foo(){
>>>>>> int zero = (INT_MAX+1)*0;
>>>>>> return zero;
>>>>>> }
>>>>>>
>>>>>> int
>>>>>> main(){
>>>>>> return 0;
>>>>>> }
>>>>>>
>>>>>> This program does not transgress the bounds of undefined behavior.
>>>>
>>>>To clarify, the comments in my posting were meant to be read as
>>>>saying the given text is the entire program, and that it is strictly
>>>>conforming with respect to conforming hosted implementations.
>>>>(Incidentally, given the rules for freestanding implementations, I'm
>>>>not sure that it is even possible for any program to be strictly
>>>>conforming with respect to conforming freestanding implementations.
>>>>In any case my statements were meant only in the context of hosted
>>>>implementations.)
>>>
>>> Ok.
>>>
>>>>> [snip]
>>>>> Perhaps you mean that this is irrelevant because `foo` is not
>>>>> invoked, but I see no reason why that need be the case in e.g.
>>>>> a freestanding environment.
>>>>
>>>>I explained the context of my previous statements above. Sorry for
>>>>not saying that in the original message.
>>>>
>>>>> In a hosted environment, I don't
>>>>> think anything explicitly prevents `foo` from being called after
>>>>> `main` returns (though I can't imagine that would happen in real
>>>>> life; it would be weird if it did).
>>>>
>>>>The semantics described in the ISO C standard don't admit that
>>>>possibility.
>>>
>>> Could you please point to where it says this, in the C standard?
>>>
>>> I cannot find anything that says that arbitrary code cannot run
>>> after `main()` returns, and I don't see how that could possibly
>>> be true.
>>
>>N3220 5.1.2.4, Program semantics.
>>
>>It defines the *observable behavior* of a program, which consists of
>>accesses to volatile objects, data written to files, and I/O dynamics of
>>interactive devices.
>
> Yes, but it does so for strictly-conforming programs with no UB.
It does so for programs in general, not just strictly conforming
ones. If a program has undefined behavior, all bets are off,
but for example a program that evaluates `printf("%d\n", INT_MAX)`
is not strictly conforming, but it's fully subject to 5.1.2.4.
> To understand conformance, we have to jump over to section 4,
> which explicitly says that, 'Undefined behavior is otherwise
> indicated in this document by the words "undefined behavior" or
> by the omission of any explicit definition of behavior.' As it
> does not say that a program with an instance of undefined
> behavior in an integer constant expression that is not executed
> must otherwise behave in any given manner, what the program does
> is undefined. A constaint violation mandates a diagnostic, but
> beyond that, the standard is (AFAICT) silent.
I don't think an integer constant expression can have undefined
behavior. INT_MAX+1 and 1/0 are not constant expressions, because
neither "evaluate(s) to a constant that is in the range of
representable values for its type".
I claim that an expression that looks like a constant expression
*isn't* a constant-expression if it doesn't appear in a context
that requires a constant-expression.
The program in question, quoted above, has:
int zero = (INT_MAX+1)*0;
`(INT_MAX+1)*0` is not a constant expression, not because of the
overflow, but because a constant expression is not required in
that context. "constant-expression" is defined by a production in
the grammar (it reduces to "conditional-expression"). Even in
int n = 42;
42 is not a a constant expression, because the grammar doesn't
call for a constant expression in that context -- even though it
looks like one. Similarly, in `a + b * c`, `a + b` looks like an
additive expression, but it isn't one. (Not a perfect analogy.)
> Undefined Behavior, in turn, is not defined as specific only to
> execution: the standard simply says that it is "behavior, upon
> use of a *nonportable or erroneous program construct*..." for
> which there are no requirements, and there are examples of
> things that are explicitly UB at translation time, such as
> improperly terminated lexemes and so forth.
Yes, there are constructs that are explicitly UB at translation time.
(I think that's unfortunate, and there are efforts to clear up some
such cases in C2y.)
Signed integer overflow is not one of those constructs.
Any undefined behavior from evaluating INT_MAX+1 happens during
execution (barring constraint violations).
> Furthermore, the expression above is obviously an integer
> constant expression as defined by sec 6.6 para 8. Section 6.6,
> para 4, reads in part, "Each constant expression shall evaluate
> to a constant that is in the range of representable values for
> its type." The expression, `(INT_MAX+1)*0` violates this
> constraint, and so therefore a diagnostic is mandated as per
> sec 5.1.1.3 para 1. That it appears in code that is not
> obviously called from `main` doesn't change that.
It satisfies the requirements for an integer constant expression in
6.6p8, but it violates the constraint in 6.6p4. (I presume that an
"integer constant expression" must be a "constant expression".)
But since "constant-expression" is a grammatical production,
it doesn't have to satisfy that constraint, and no diagnostic
is required. (A warning is certainly permitted.)
Similarly, this:
int n = INT_MAX + 1;
at block scope doesn't require a diagnostic, though of course it
has undefined behavior -- but at file scope, the initializer is a
constant expression, so that would be a constraint violation.
> Morever, sec 6.6 para 17 says that, "the semantic rules for
> evaluation of a constant expression are the same as for
> nonconstant expressions." This brings us back to 5.1.2.4,
> though I submit that para (4) is a stronger argument for what
> you and Tim are saying, as it reads in part, "An actual
> implementation is not required to evaluate part of an expression
> if it can deduce that its value is not used and that no needed
> side effects are produced (including any caused by calling a
> function or through volatile access to an object)." I interpret
> this to mean that, if the implementation can determine that
> there is no way that `foo` can be called, it does not _have_ to
> evaluate the above expression. However, it must satisfy the
> range constraint from section 6.6, so it likely will, and in any
> event, the standard does not say that it, "shall not" evaluate
> it, or when.
Overflow in a constant expression is not undefined behavior. It's a
constraint violation. But that doesn't apply here, because the
initializer is not a constant expression. (Sorry if I'm repeating
myself.)
> Once the compiler does that, if it does, and observes UB, the
> standard is silent on what requirements it imposes, which means
> the behavior is undefined. I see no reason it couldn't arrange
> to invoke `foo` at that point.
Any UB in the program would occur during execution, and in fact
it *won't* occur during execution because foo() isn't called.
A compiler can't generate code with arbitrary behavior just because
it can't prove that there will be no UB. If it could, every signed
or floating-point arithmetic operation with unknown operand values
would grant the same permission.
> So no, I do not see how execution according to the rules of the
> abstract machine is not guaranteed, here. I certainly see no
> way in which this can be regarded as a strictly conforming
> program.
foo()'s behavior would be undefined if it were called. It *isn't*
called, so there's no actual UB. The program does not violate any
of the other requirements for strict conformance.
>>If the usual "Hello, world" program prints "Hello, world" followed
>>by "Goodbye", the implementation is non-conforming. If it formats
>>my hard drive after printing "Goodbye", it's non-conforming and
>>dangerous.
>
> Two separate things. My point earlier was that code can
> obviously run after `main` terminates. Moreoever, I can't
> imagine what would _prevent_ a runtime system that invokes
> `main` from doing something like printing, "PROGRAM STOPPED"
> after `main` returned. C imposes no requirements here.
Yes, it does. An OS can print "PROGRAM STOPPED", but not as part
of the execution of the program. On my system, a shell prompt is
printed after a program terminates, but not by the program. If I
execute a "hello, world" program with its output redirected to a file
(on a system that supports that), the resulting file cannot contain
"PROGRAM STOPPED". The requirements in 5.1.2.4 specify both what
the execution of a program must do and what it must not do.
> Whether `foo` could be invoked after, I think, is undefined.
>
>>>>Whether foo() has external linkage or internal
>>>>linkage doesn't change that.
>>>
>>> I disagree. There's no possible way for the implementation to
>>> know whether a function with external linkage will be ultimately
>>> invoked or not; consider a system that supports loadable shared
>>> modules. Nothing prevents even this simple program from being
>>> compiled as a shared module, dynamically loaded, the loading
>>> program explicitly searching for and finding the symbol
>>> corresponding to the `foo` function, and invoking it.
>>
>>Remember that linking is translation phase 8. The compiler is not
>>the entire implementation.
>
> Exactly my point. The compiler cannot know how `foo` might be
> used, or how the translated object might be exercised. There's
> I don't see how it could possibly know that, given that `foo`
> has external linkage.
We were presented with a complete translation unit that included a
function definition for "main". It's a complete program. There's no
valid way for some other program to call foo. If OS provided such
a mechanism, it would be outside the scope of C.
>>> Hence, the compiler _must_ treat with UB as written, which is
>>> why `ubsan` inserts trapping code in `foo`.
>>
>>I don't know what "_must_ treat with UB" means.
>>
>>foo() has undefined behavior if it's called, so replacing its
>>body with trapping code is valid. But (I'm reasonably sure that)
>>an implementation cannot reject a program just because it can't
>>prove that it has no undefined behavior during execution. It can
>>reject it if it can prove that it *always* has undefined behavior
>>during execution.
>
> What I'm saying is that, `foo` has undefined behavior _period_.
> That's manifest in an integer constant expression, whether it is
> executed at runtime or not. I believe that the standard forces
> the expression to be evaluated at translation time, via the
> "shall" mandate when checking the constraint on the range in sec
> 6.6 para 4. Further, that evaluation must happen in accordance
> with the rules of the abstract machine, as per 5.1.2.4 para 17.
> The diagnostic is mandated, as is the translation-time
> evaluation. The expression is itself manifestly exhibits UB,
> and so therefore the result of the rest of the translation is
> undefined.
foo is a function. foo does not have undefined behavior; it has no
behavior at all. A *call* to foo during execution has undefined
behavior. (`foo;` is a statement-expression that does nothing;
it does not have undefined behavior.)
[SNIP]
I think the question of whether the initializer is a
constant-expression or not has caused some not entirely relevant
confusion.
Here's another example that avoids that issue.
#include <limits.h>
int foo(void) {
int zero;
zero = INT_MAX;
zero ++;
zero *= 0;
return zero;
}
int main(void) {
return 0;
}
Given my grammatical argument above, I would say that this program
has no constant expressions. Whether that argument is correct or
not, it certainly has no constant expressions that violate any
constraint or that have undefined behavior. Evaluating `zero ++`
(which doesn't even pretend to be a constant expression) would have
run-time undefined behavior -- *if* foo() were ever called.
And given this translation unit, I don't think there's any way to
construct a multi-TU program that calls foo, so a compiler *can*
determine that foo is never called (but there's no requirement to
do so, or to make any use of that information).
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-06 03:10 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <110032s$clq$1@reader1.panix.com> |
| In reply to | #399731 |
In article <10vt7b9$pi3s$1@kst.eternal-september.org>,
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>> In article <10vsnl7$lkmu$1@kst.eternal-september.org>,
>> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>> In article <865x3yd21n.fsf@linuxsc.com>,
>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>>>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>>>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>[...]
>>>>>>> There's an important distinction to make here. Consider this
>>>>>>> program:
>>>>>>>
>>>>>>> #include <limits.h>
>>>>>>>
>>>>>>> int
>>>>>>> foo(){
>>>>>>> int zero = (INT_MAX+1)*0;
>>>>>>> return zero;
>>>>>>> }
>>>>>>>
>>>>>>> int
>>>>>>> main(){
>>>>>>> return 0;
>>>>>>> }
>>>>>>>
>>>>>>> This program does not transgress the bounds of undefined behavior.
>>>>>
>>>>>To clarify, the comments in my posting were meant to be read as
>>>>>saying the given text is the entire program, and that it is strictly
>>>>>conforming with respect to conforming hosted implementations.
>>>>>(Incidentally, given the rules for freestanding implementations, I'm
>>>>>not sure that it is even possible for any program to be strictly
>>>>>conforming with respect to conforming freestanding implementations.
>>>>>In any case my statements were meant only in the context of hosted
>>>>>implementations.)
>>>>
>>>> Ok.
>>>>
>>>>>> [snip]
>>>>>> Perhaps you mean that this is irrelevant because `foo` is not
>>>>>> invoked, but I see no reason why that need be the case in e.g.
>>>>>> a freestanding environment.
>>>>>
>>>>>I explained the context of my previous statements above. Sorry for
>>>>>not saying that in the original message.
>>>>>
>>>>>> In a hosted environment, I don't
>>>>>> think anything explicitly prevents `foo` from being called after
>>>>>> `main` returns (though I can't imagine that would happen in real
>>>>>> life; it would be weird if it did).
>>>>>
>>>>>The semantics described in the ISO C standard don't admit that
>>>>>possibility.
>>>>
>>>> Could you please point to where it says this, in the C standard?
>>>>
>>>> I cannot find anything that says that arbitrary code cannot run
>>>> after `main()` returns, and I don't see how that could possibly
>>>> be true.
>>>
>>>N3220 5.1.2.4, Program semantics.
>>>
>>>It defines the *observable behavior* of a program, which consists of
>>>accesses to volatile objects, data written to files, and I/O dynamics of
>>>interactive devices.
>>
>> Yes, but it does so for strictly-conforming programs with no UB.
>
>It does so for programs in general, not just strictly conforming
>ones. If a program has undefined behavior, all bets are off,
>but for example a program that evaluates `printf("%d\n", INT_MAX)`
>is not strictly conforming, but it's fully subject to 5.1.2.4.
>
>> To understand conformance, we have to jump over to section 4,
>> which explicitly says that, 'Undefined behavior is otherwise
>> indicated in this document by the words "undefined behavior" or
>> by the omission of any explicit definition of behavior.' As it
>> does not say that a program with an instance of undefined
>> behavior in an integer constant expression that is not executed
>> must otherwise behave in any given manner, what the program does
>> is undefined. A constaint violation mandates a diagnostic, but
>> beyond that, the standard is (AFAICT) silent.
>
>I don't think an integer constant expression can have undefined
>behavior. INT_MAX+1 and 1/0 are not constant expressions, because
>neither "evaluate(s) to a constant that is in the range of
>representable values for its type".
>
>I claim that an expression that looks like a constant expression
>*isn't* a constant-expression if it doesn't appear in a context
>that requires a constant-expression.
That's a bold claim, but I think I see why you're saying that.
>The program in question, quoted above, has:
>
> int zero = (INT_MAX+1)*0;
>
>`(INT_MAX+1)*0` is not a constant expression, not because of the
>overflow, but because a constant expression is not required in
>that context. "constant-expression" is defined by a production in
>the grammar (it reduces to "conditional-expression"). Even in
>
> int n = 42;
>
>42 is not a a constant expression, because the grammar doesn't
>call for a constant expression in that context -- even though it
>looks like one. Similarly, in `a + b * c`, `a + b` looks like an
>additive expression, but it isn't one. (Not a perfect analogy.)
Right; I see what you mean. In this case, the
`assignment-expression` production applies, not
`constant-expression`.
>> Undefined Behavior, in turn, is not defined as specific only to
>> execution: the standard simply says that it is "behavior, upon
>> use of a *nonportable or erroneous program construct*..." for
>> which there are no requirements, and there are examples of
>> things that are explicitly UB at translation time, such as
>> improperly terminated lexemes and so forth.
>
>Yes, there are constructs that are explicitly UB at translation time.
>(I think that's unfortunate, and there are efforts to clear up some
>such cases in C2y.)
It's unclear to me how it could be any other way. If UB was
_only_ an issue at runtime, then how could a compiler take
advantage of it to perform optimizations during translation?
We know that compilers do this.
>Signed integer overflow is not one of those constructs.
This I'm not sure I agree with. It the compiler detects signed
integer overflow in (perhaps not relevant in _this_ example) an
integer constant expression, I still don't see anthing that
makes that anything other than UB. It's a constaint violation,
sure, but nothing says it is not also UB.
>Any undefined behavior from evaluating INT_MAX+1 happens during
>execution (barring constraint violations).
I'm not sure the standard says that. The standard says this
happens during _evaluation_, and that evaluation must be
performed in accordance with the rules of the abstract syntax
machine. But it doesn't precisely specify _when_ evaluation
takes place, and in particular, there are places in the standard
that explicitly mention evaluation during translation. I still
don't see anything that prohibits a compiler from evaluating
that expression at compile time (indeed, it clearly does, as it
generates a diagnostic about the overflow).
I suppose that changes the matter: does the language merely
leave that unspecified, in which case, this program is not
strictly conforming, or does it say that it _cannot_ make any
translation-time decisions about it? I cannot find a satisfying
argument for the latter.
>> Furthermore, the expression above is obviously an integer
>> constant expression as defined by sec 6.6 para 8. Section 6.6,
>> para 4, reads in part, "Each constant expression shall evaluate
>> to a constant that is in the range of representable values for
>> its type." The expression, `(INT_MAX+1)*0` violates this
>> constraint, and so therefore a diagnostic is mandated as per
>> sec 5.1.1.3 para 1. That it appears in code that is not
>> obviously called from `main` doesn't change that.
>
>It satisfies the requirements for an integer constant expression in
>6.6p8, but it violates the constraint in 6.6p4. (I presume that an
>"integer constant expression" must be a "constant expression".)
>But since "constant-expression" is a grammatical production,
>it doesn't have to satisfy that constraint, and no diagnostic
>is required. (A warning is certainly permitted.)
Fair point. It's grammatical position makes it an
assignment-expression. I clearly misinterpreted that before.
>Similarly, this:
> int n = INT_MAX + 1;
>at block scope doesn't require a diagnostic, though of course it
>has undefined behavior -- but at file scope, the initializer is a
>constant expression, so that would be a constraint violation.
Right. The semantics of this are defined in sec 6.7.11 para 5.
>> Morever, sec 6.6 para 17 says that, "the semantic rules for
>> evaluation of a constant expression are the same as for
>> nonconstant expressions." This brings us back to 5.1.2.4,
>> though I submit that para (4) is a stronger argument for what
>> you and Tim are saying, as it reads in part, "An actual
>> implementation is not required to evaluate part of an expression
>> if it can deduce that its value is not used and that no needed
>> side effects are produced (including any caused by calling a
>> function or through volatile access to an object)." I interpret
>> this to mean that, if the implementation can determine that
>> there is no way that `foo` can be called, it does not _have_ to
>> evaluate the above expression. However, it must satisfy the
>> range constraint from section 6.6, so it likely will, and in any
>> event, the standard does not say that it, "shall not" evaluate
>> it, or when.
>
>Overflow in a constant expression is not undefined behavior. It's a
>constraint violation. But that doesn't apply here, because the
>initializer is not a constant expression. (Sorry if I'm repeating
>myself.)
Where does it say that UB and constraint violations are mutually
exclusive? I don't see any such statement in the standard. Am
I missing it?
The standard says that if a constraint is violated, a diagnostic
must be emitted, regardless of whether or not the constraint
violation is the result of something that is UB not; that is, if
a constraint violation occurs due to something that is UB, the
implementation must still emit a diagnostic: UB is not an escape
hatch from that requirement.
It also says, 'If a "shall" or "shall not" requirement that
appears outside of a constraint or runtime-constraint is
violated, the behavior is undefined. Undefined behavior is
otherwise indicated in this document by the words "undefined
behavior" or by the omission of any explicit definition of
behavior.' However, that does not preclude such behavior being
undefined; it just means that the words "shall" and "shall not"
in a constraint violation do not a priori describe behavior vis
definition.
>> Once the compiler does that, if it does, and observes UB, the
>> standard is silent on what requirements it imposes, which means
>> the behavior is undefined. I see no reason it couldn't arrange
>> to invoke `foo` at that point.
>
>Any UB in the program would occur during execution,
I suppose; but it's not clear to me that UB is tied _only_ to
execution time.
The standard is explicit that there _are_ things that are
evaluated at translation time, like the initializer for an
object with storage class `constexpr`. It is not clear me that
a compiler is otherwise _prohibited_ from evaluating an
expression during translation; indeed, one could imagine it
doing so to perform constant folding, and I do not believe there
exists any normative text defining it as such.
I realize this is an extreme interpretation, and not one that is
not widely shared. Personally, I think it's rather silly.
However, I that is _a_ danger of the informality of the C
specification; it does not define the semantics of the abstract
machine in the formally precise way that, say, the SML spec
defines that language's semantics. Rather, it informally
specifies them in prose, and that prose is ambiguous.
Probably much good would be done if C's semantics _were_
rigorously defined, but they are not. Thus, they are open to
radical interpretation, and as extreme as those may be, I do not
see how the normative text of the standard explicitly
_prohibits_ them.
>and in fact
>it *won't* occur during execution because foo() isn't called.
>A compiler can't generate code with arbitrary behavior just because
>it can't prove that there will be no UB. If it could, every signed
>or floating-point arithmetic operation with unknown operand values
>would grant the same permission.
But that's not the situation here. The situation is that the
compiler can prove that something _is_ UB.
Regardless, I think you highlighted an actual problem with the
spec; I don't think that behavior is _explicitly_ prohibited,
therefore, it is likely undefined, but at a minimum unspecified,
whether it actually could happen. If the argument against that
is that this renders the language essentially unusuable, then
my response is, "yeah, well, welcome to programming in C in the
2020s." Most compilers would never be that extreme, but I see
no evidence that it would not be an invalid reading of the
literal text of the standard if they did.
>> So no, I do not see how execution according to the rules of the
>> abstract machine is not guaranteed, here. I certainly see no
>> way in which this can be regarded as a strictly conforming
>> program.
>
>foo()'s behavior would be undefined if it were called. It *isn't*
>called, so there's no actual UB. The program does not violate any
>of the other requirements for strict conformance.
I understand _what_ you're saying: despite the expression itself
manifesting undefined behavior, in this case it's not UB because
`foo` is never executed. What I'm saying is that I don't see
anything in the standard that restricts UB to _only_ executed
code. A reputable compiler obviously instruments `foo` with
code to trap into ubsan; if it's not UB, since it's not
executed, then why do so? Granted, that's not evidence of
anything other than the behavior of those compilers, but still.
It is clearly the _intent_ that this be a strictly conforming
program. The C standard, as an imprecise, informal document,
cannot guarantee it.
>>>If the usual "Hello, world" program prints "Hello, world" followed
>>>by "Goodbye", the implementation is non-conforming. If it formats
>>>my hard drive after printing "Goodbye", it's non-conforming and
>>>dangerous.
>>
>> Two separate things. My point earlier was that code can
>> obviously run after `main` terminates. Moreoever, I can't
>> imagine what would _prevent_ a runtime system that invokes
>> `main` from doing something like printing, "PROGRAM STOPPED"
>> after `main` returned. C imposes no requirements here.
>
>Yes, it does. An OS can print "PROGRAM STOPPED", but not as part
>of the execution of the program. On my system, a shell prompt is
>printed after a program terminates, but not by the program. If I
>execute a "hello, world" program with its output redirected to a file
>(on a system that supports that), the resulting file cannot contain
>"PROGRAM STOPPED". The requirements in 5.1.2.4 specify both what
>the execution of a program must do and what it must not do.
Files are a separate case. There's no guarantee that the
standard output refers to a file; it may well refer to an
"interactive device", the semantics of which are (necessarily)
unspecified.
Here's an example: consider an interactive user who uses a
screen reader device. Suppose that user makes use of an
implementation that includes runtime support for that device,
and that precedes invocation of `main` with a command sequence
causing the screen reader to (perhaps) change intonation; and
suceeds return from main by outputing another command sequence
that resets to the original state.
I do not see how C could prohibit that, assuming that the
implementation takes care to detect whether standard output
really refers to the screen reader, and does emit the control
sequences if output is redirected to a file. Another user who
runs that same program without a screen reader may see the
standard text printed on the screen, without the control
sequence sandwich.
I don't think a conforming implementation can prohibit that kind
of thing.
>>>>>Whether foo() has external linkage or internal
>>>>>linkage doesn't change that.
>>>>
>>>> I disagree. There's no possible way for the implementation to
>>>> know whether a function with external linkage will be ultimately
>>>> invoked or not; consider a system that supports loadable shared
>>>> modules. Nothing prevents even this simple program from being
>>>> compiled as a shared module, dynamically loaded, the loading
>>>> program explicitly searching for and finding the symbol
>>>> corresponding to the `foo` function, and invoking it.
>>>
>>>Remember that linking is translation phase 8. The compiler is not
>>>the entire implementation.
>>
>> Exactly my point. The compiler cannot know how `foo` might be
>> used, or how the translated object might be exercised. There's
>> I don't see how it could possibly know that, given that `foo`
>> has external linkage.
>
>We were presented with a complete translation unit that included a
>function definition for "main". It's a complete program. There's no
>valid way for some other program to call foo. If OS provided such
>a mechanism, it would be outside the scope of C.
Given an excessively pedantic and literal reading of the text of
the standard, I don't think an implementation is explicitly
prohibited from evaluating the initializer at translation time,
deducing that the behavior is undefined, and blaming it on the
program, at which point, all bets are off.
>>>> Hence, the compiler _must_ treat with UB as written, which is
>>>> why `ubsan` inserts trapping code in `foo`.
>>>
>>>I don't know what "_must_ treat with UB" means.
>>>
>>>foo() has undefined behavior if it's called, so replacing its
>>>body with trapping code is valid. But (I'm reasonably sure that)
>>>an implementation cannot reject a program just because it can't
>>>prove that it has no undefined behavior during execution. It can
>>>reject it if it can prove that it *always* has undefined behavior
>>>during execution.
>>
>> What I'm saying is that, `foo` has undefined behavior _period_.
>> That's manifest in an integer constant expression, whether it is
>> executed at runtime or not. I believe that the standard forces
>> the expression to be evaluated at translation time, via the
>> "shall" mandate when checking the constraint on the range in sec
>> 6.6 para 4. Further, that evaluation must happen in accordance
>> with the rules of the abstract machine, as per 5.1.2.4 para 17.
>> The diagnostic is mandated, as is the translation-time
>> evaluation. The expression is itself manifestly exhibits UB,
>> and so therefore the result of the rest of the translation is
>> undefined.
>
>foo is a function. foo does not have undefined behavior; it has no
>behavior at all. A *call* to foo during execution has undefined
>behavior. (`foo;` is a statement-expression that does nothing;
>it does not have undefined behavior.)
The _evaluation_ of that expression in `foo` has undefined
behavior. The standard does not say that it _cannot_ be
evaluated at translation time.
>[SNIP]
>
>I think the question of whether the initializer is a
>constant-expression or not has caused some not entirely relevant
>confusion.
>
>Here's another example that avoids that issue.
>
>#include <limits.h>
>
>int foo(void) {
> int zero;
> zero = INT_MAX;
> zero ++;
> zero *= 0;
> return zero;
>}
>
>int main(void) {
> return 0;
>}
>
>Given my grammatical argument above, I would say that this program
>has no constant expressions.
Agreed, if by "constant expressions" you mean those mandated to
use the `constant-expression` grammatical production.
>Whether that argument is correct or
>not, it certainly has no constant expressions that violate any
>constraint or that have undefined behavior. Evaluating `zero ++`
>(which doesn't even pretend to be a constant expression) would have
>run-time undefined behavior -- *if* foo() were ever called.
Let me turn this around in two ways: suppose that the
translation unit _only_ included `foo`. Could the compiler
deduce that the behavior of `foo`, if called, is undefined? If
not, why not?
Second, suppose that `foo` _were_ called, could the compiler
replace this with a program that was the equivalent of,
`int main(void) {printf("check your nose"); abort();}`? If so
why? If not, why not?
>And given this translation unit, I don't think there's any way to
>construct a multi-TU program that calls foo, so a compiler *can*
>determine that foo is never called (but there's no requirement to
>do so, or to make any use of that information).
This is the crux of my point, as well. There's not requirement
for the translator to _not_ evaluate the expression and become
privy to UB.
Would it be stupid if a compiler did that? Yes. Do existing
compilers do so? No, not that I'm aware of. Would some dweeb
nerd compiler douche who thinks this would make a compiler
benchmark some microfraction of a percent faster take advantage
of that? I absolutely think so, yes.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-05 23:50 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <1100g0e$1lt8i$1@kst.eternal-september.org> |
| In reply to | #399760 |
cross@spitfire.i.gajendra.net (Dan Cross) writes:
> In article <10vt7b9$pi3s$1@kst.eternal-september.org>,
> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>> In article <10vsnl7$lkmu$1@kst.eternal-september.org>,
>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>>> In article <865x3yd21n.fsf@linuxsc.com>,
>>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>>>>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>>>>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>>[...]
>>>>>>>> There's an important distinction to make here. Consider this
>>>>>>>> program:
>>>>>>>>
>>>>>>>> #include <limits.h>
>>>>>>>>
>>>>>>>> int
>>>>>>>> foo(){
>>>>>>>> int zero = (INT_MAX+1)*0;
>>>>>>>> return zero;
>>>>>>>> }
>>>>>>>>
>>>>>>>> int
>>>>>>>> main(){
>>>>>>>> return 0;
>>>>>>>> }
>>>>>>>>
>>>>>>>> This program does not transgress the bounds of undefined behavior.
>>>>>>
>>>>>>To clarify, the comments in my posting were meant to be read as
>>>>>>saying the given text is the entire program, and that it is strictly
>>>>>>conforming with respect to conforming hosted implementations.
>>>>>>(Incidentally, given the rules for freestanding implementations, I'm
>>>>>>not sure that it is even possible for any program to be strictly
>>>>>>conforming with respect to conforming freestanding implementations.
>>>>>>In any case my statements were meant only in the context of hosted
>>>>>>implementations.)
>>>>>
>>>>> Ok.
>>>>>
>>>>>>> [snip]
>>>>>>> Perhaps you mean that this is irrelevant because `foo` is not
>>>>>>> invoked, but I see no reason why that need be the case in e.g.
>>>>>>> a freestanding environment.
>>>>>>
>>>>>>I explained the context of my previous statements above. Sorry for
>>>>>>not saying that in the original message.
>>>>>>
>>>>>>> In a hosted environment, I don't
>>>>>>> think anything explicitly prevents `foo` from being called after
>>>>>>> `main` returns (though I can't imagine that would happen in real
>>>>>>> life; it would be weird if it did).
>>>>>>
>>>>>>The semantics described in the ISO C standard don't admit that
>>>>>>possibility.
>>>>>
>>>>> Could you please point to where it says this, in the C standard?
>>>>>
>>>>> I cannot find anything that says that arbitrary code cannot run
>>>>> after `main()` returns, and I don't see how that could possibly
>>>>> be true.
>>>>
>>>>N3220 5.1.2.4, Program semantics.
>>>>
>>>>It defines the *observable behavior* of a program, which consists of
>>>>accesses to volatile objects, data written to files, and I/O dynamics of
>>>>interactive devices.
>>>
>>> Yes, but it does so for strictly-conforming programs with no UB.
>>
>>It does so for programs in general, not just strictly conforming
>>ones. If a program has undefined behavior, all bets are off,
>>but for example a program that evaluates `printf("%d\n", INT_MAX)`
>>is not strictly conforming, but it's fully subject to 5.1.2.4.
>>
>>> To understand conformance, we have to jump over to section 4,
>>> which explicitly says that, 'Undefined behavior is otherwise
>>> indicated in this document by the words "undefined behavior" or
>>> by the omission of any explicit definition of behavior.' As it
>>> does not say that a program with an instance of undefined
>>> behavior in an integer constant expression that is not executed
>>> must otherwise behave in any given manner, what the program does
>>> is undefined. A constaint violation mandates a diagnostic, but
>>> beyond that, the standard is (AFAICT) silent.
>>
>>I don't think an integer constant expression can have undefined
>>behavior. INT_MAX+1 and 1/0 are not constant expressions, because
>>neither "evaluate(s) to a constant that is in the range of
>>representable values for its type".
>>
>>I claim that an expression that looks like a constant expression
>>*isn't* a constant-expression if it doesn't appear in a context
>>that requires a constant-expression.
>
> That's a bold claim, but I think I see why you're saying that.
>
>>The program in question, quoted above, has:
>>
>> int zero = (INT_MAX+1)*0;
>>
>>`(INT_MAX+1)*0` is not a constant expression, not because of the
>>overflow, but because a constant expression is not required in
>>that context. "constant-expression" is defined by a production in
>>the grammar (it reduces to "conditional-expression"). Even in
>>
>> int n = 42;
>>
>>42 is not a a constant expression, because the grammar doesn't
>>call for a constant expression in that context -- even though it
>>looks like one. Similarly, in `a + b * c`, `a + b` looks like an
>>additive expression, but it isn't one. (Not a perfect analogy.)
>
> Right; I see what you mean. In this case, the
> `assignment-expression` production applies, not
> `constant-expression`.
>
>>> Undefined Behavior, in turn, is not defined as specific only to
>>> execution: the standard simply says that it is "behavior, upon
>>> use of a *nonportable or erroneous program construct*..." for
>>> which there are no requirements, and there are examples of
>>> things that are explicitly UB at translation time, such as
>>> improperly terminated lexemes and so forth.
>>
>>Yes, there are constructs that are explicitly UB at translation time.
>>(I think that's unfortunate, and there are efforts to clear up some
>>such cases in C2y.)
>
> It's unclear to me how it could be any other way. If UB was
> _only_ an issue at runtime, then how could a compiler take
> advantage of it to perform optimizations during translation?
> We know that compilers do this.
There are instances of undefined behavior that depend on specific
characteristics of a source file, not on run-time behavior.
The first example I found (N3220) is in the description of
translation phase 4, 5.1.1.2:
If a character sequence that matches the syntax of a universal
character name is produced by token concatenation (6.10.5.3), the
behavior is undefined.
That's something that can be detected during compilation. It would
be far better if it were either well defined or a syntax rule
violation. And in fact the latest C2y draft doesn't have that
wording. There's an ongoing effort to clean up this kind of thing.
That's not the kind of UB I'm talking about.
>>Signed integer overflow is not one of those constructs.
>
> This I'm not sure I agree with. It the compiler detects signed
> integer overflow in (perhaps not relevant in _this_ example) an
> integer constant expression, I still don't see anthing that
> makes that anything other than UB. It's a constaint violation,
> sure, but nothing says it is not also UB.
An implementation can choose to successfully translate a program that
violates a constraint. In my opinion, the resulting program has (or
should be considered to have) undefined behavior, but the standard
doesn't explicitly say so. My argument is based on the definition
of "constraint": "restriction, either syntactic or semantic,
by which the exposition of language elements is interpreted".
If a constraint is violated, I argue that there is no basis for
interpreting the exposition of language elements, and therefore no
definition of the behavior.
Other interpretations are possible.
So if an overflow in an ICE has undefined behavior, it's merely
an instance of this more general principle, which might even not
be valid.
An unambiguous case is:
case INT_MAX+1:
That's a constraint violation. The expression is required to be an
ICE, but it doesn't "evaluate to a constant that is in the range
of representable values for its type" (unless you want to argue
that it can evaluate to INT_MIN for a particular implementation,
but I really dislike the implications of that). If there's UB,
it's because of the constraint violation. (In fact I'd expect most
compilers to reject it, so there's no behavior at all.)
On the other hand, this:
int n = INT_MAX;
n++;
has undefined behavior and is not a constraint violation. A note on the
definition of "undefined behavior" says:
Possible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during
translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of a
diagnostic message), to terminating a translation or execution (with
the issuance of a diagnostic message).
So a compiler can reject it *if* it can prove that the undefined
behavior will always occur. The standard is not 100% clear about
whether it can be rejected if the code is never executed, or is
executed conditionally, but I think that's not permitted, or at least
it shouldn't be. Rejecting code because the compiler can't prove
the behavior is undefined has some very unpleasant implications.
>>Any undefined behavior from evaluating INT_MAX+1 happens during
>>execution (barring constraint violations).
>
> I'm not sure the standard says that. The standard says this
> happens during _evaluation_, and that evaluation must be
> performed in accordance with the rules of the abstract syntax
> machine. But it doesn't precisely specify _when_ evaluation
> takes place, and in particular, there are places in the standard
> that explicitly mention evaluation during translation. I still
> don't see anything that prohibits a compiler from evaluating
> that expression at compile time (indeed, it clearly does, as it
> generates a diagnostic about the overflow).
>
> I suppose that changes the matter: does the language merely
> leave that unspecified, in which case, this program is not
> strictly conforming, or does it say that it _cannot_ make any
> translation-time decisions about it? I cannot find a satisfying
> argument for the latter.
Ok, given:
case INT_MAX+1:
a compiler could issue the required diagnostic for the constraint
violation as a non-fatal warning, then generate code that executes
an ADD instruction with operands INT_MAX and 1. That would be
conforming but silly. The compiler has to determine that INT_MAX+1
overflows anyway so it can issue the diagnostic.
>>> Furthermore, the expression above is obviously an integer
>>> constant expression as defined by sec 6.6 para 8. Section 6.6,
>>> para 4, reads in part, "Each constant expression shall evaluate
>>> to a constant that is in the range of representable values for
>>> its type." The expression, `(INT_MAX+1)*0` violates this
>>> constraint, and so therefore a diagnostic is mandated as per
>>> sec 5.1.1.3 para 1. That it appears in code that is not
>>> obviously called from `main` doesn't change that.
>>
>>It satisfies the requirements for an integer constant expression in
>>6.6p8, but it violates the constraint in 6.6p4. (I presume that an
>>"integer constant expression" must be a "constant expression".)
>>But since "constant-expression" is a grammatical production,
>>it doesn't have to satisfy that constraint, and no diagnostic
>>is required. (A warning is certainly permitted.)
>
> Fair point. It's grammatical position makes it an
> assignment-expression. I clearly misinterpreted that before.
>
>>Similarly, this:
>> int n = INT_MAX + 1;
>>at block scope doesn't require a diagnostic, though of course it
>>has undefined behavior -- but at file scope, the initializer is a
>>constant expression, so that would be a constraint violation.
>
> Right. The semantics of this are defined in sec 6.7.11 para 5.
>
>>> Morever, sec 6.6 para 17 says that, "the semantic rules for
>>> evaluation of a constant expression are the same as for
>>> nonconstant expressions." This brings us back to 5.1.2.4,
>>> though I submit that para (4) is a stronger argument for what
>>> you and Tim are saying, as it reads in part, "An actual
>>> implementation is not required to evaluate part of an expression
>>> if it can deduce that its value is not used and that no needed
>>> side effects are produced (including any caused by calling a
>>> function or through volatile access to an object)." I interpret
>>> this to mean that, if the implementation can determine that
>>> there is no way that `foo` can be called, it does not _have_ to
>>> evaluate the above expression. However, it must satisfy the
>>> range constraint from section 6.6, so it likely will, and in any
>>> event, the standard does not say that it, "shall not" evaluate
>>> it, or when.
>>
>>Overflow in a constant expression is not undefined behavior. It's a
>>constraint violation. But that doesn't apply here, because the
>>initializer is not a constant expression. (Sorry if I'm repeating
>>myself.)
>
> Where does it say that UB and constraint violations are mutually
> exclusive? I don't see any such statement in the standard. Am
> I missing it?
It doesn't.
As a practical matter, when I look at C code, if it violates a
constraint, I typically don't care about its behavior. I want it
to be rejected at compile time (unless it's deliberately taking
advantage of a documented extension). I'll fix it rather than
worrying about its behavior.
(Unless the code has somehow gotten into production and it's my
job to analyze how it misbehaves.)
Yes, a program that violates a constraint can have run-time behavior if
the compiler chooses not to reject it, and that behavior may be
undefined.
> The standard says that if a constraint is violated, a diagnostic
> must be emitted, regardless of whether or not the constraint
> violation is the result of something that is UB not; that is, if
> a constraint violation occurs due to something that is UB, the
> implementation must still emit a diagnostic: UB is not an escape
> hatch from that requirement.
Right.
> It also says, 'If a "shall" or "shall not" requirement that
> appears outside of a constraint or runtime-constraint is
> violated, the behavior is undefined. Undefined behavior is
> otherwise indicated in this document by the words "undefined
> behavior" or by the omission of any explicit definition of
> behavior.' However, that does not preclude such behavior being
> undefined; it just means that the words "shall" and "shall not"
> in a constraint violation do not a priori describe behavior vis
> definition.
Right.
>>> Once the compiler does that, if it does, and observes UB, the
>>> standard is silent on what requirements it imposes, which means
>>> the behavior is undefined. I see no reason it couldn't arrange
>>> to invoke `foo` at that point.
>>
>>Any UB in the program would occur during execution,
>
> I suppose; but it's not clear to me that UB is tied _only_ to
> execution time.
>
> The standard is explicit that there _are_ things that are
> evaluated at translation time, like the initializer for an
> object with storage class `constexpr`. It is not clear me that
> a compiler is otherwise _prohibited_ from evaluating an
> expression during translation; indeed, one could imagine it
> doing so to perform constant folding, and I do not believe there
> exists any normative text defining it as such.
Certainly a compiler can, but need not, evaluate any expression at
compile time if it's able to:
int n;
n = 2 + 2;
I'd be surprised to see an ADD instruction in the generated code, but
a naive compiler could certainly generate one. For that matter, a
perverse compiler could generate code that adds 3 and 1 or divides 28
by 7. Anything that implements the required *observable behavior*
(5.1.2.4 Program semantics) is acceptable. Executing an ADD
instruction is not part of the observable behavior.
> I realize this is an extreme interpretation, and not one that is
> not widely shared. Personally, I think it's rather silly.
>
> However, I that is _a_ danger of the informality of the C
> specification; it does not define the semantics of the abstract
> machine in the formally precise way that, say, the SML spec
> defines that language's semantics. Rather, it informally
> specifies them in prose, and that prose is ambiguous.
There have been attempts to define C's semantics formally, but
those attempts are not part of the standard. Fully defining C's
semantics formally rather than in English would, I imagine it would
be a *lot* of work -- and fewer people would be able to understand
the specification or work on it.
> Probably much good would be done if C's semantics _were_
> rigorously defined, but they are not. Thus, they are open to
> radical interpretation, and as extreme as those may be, I do not
> see how the normative text of the standard explicitly
> _prohibits_ them.
>
>>and in fact
>>it *won't* occur during execution because foo() isn't called.
>>A compiler can't generate code with arbitrary behavior just because
>>it can't prove that there will be no UB. If it could, every signed
>>or floating-point arithmetic operation with unknown operand values
>>would grant the same permission.
>
> But that's not the situation here. The situation is that the
> compiler can prove that something _is_ UB.
In the program quoted at the top of this post, the UB occurs in
a function foo() that's never called. A compiler can replace the
body of foo() with a trap, and it can certainly warn about the UB,
but I don't believe it can reject the entire program. A clever
compiler could prove that the UB never occurs.
A naive compiler that performs no optimizations would generate
code for foo() that attempts to compute (INT_MAX+1)*0 step by
step, without recognizing the overflow, and that code would never
be executed.
> Regardless, I think you highlighted an actual problem with the
> spec; I don't think that behavior is _explicitly_ prohibited,
> therefore, it is likely undefined, but at a minimum unspecified,
> whether it actually could happen. If the argument against that
> is that this renders the language essentially unusuable, then
> my response is, "yeah, well, welcome to programming in C in the
> 2020s." Most compilers would never be that extreme, but I see
> no evidence that it would not be an invalid reading of the
> literal text of the standard if they did.
>
>>> So no, I do not see how execution according to the rules of the
>>> abstract machine is not guaranteed, here. I certainly see no
>>> way in which this can be regarded as a strictly conforming
>>> program.
>>
>>foo()'s behavior would be undefined if it were called. It *isn't*
>>called, so there's no actual UB. The program does not violate any
>>of the other requirements for strict conformance.
>
> I understand _what_ you're saying: despite the expression itself
> manifesting undefined behavior, in this case it's not UB because
> `foo` is never executed. What I'm saying is that I don't see
> anything in the standard that restricts UB to _only_ executed
> code. A reputable compiler obviously instruments `foo` with
> code to trap into ubsan; if it's not UB, since it's not
> executed, then why do so? Granted, that's not evidence of
> anything other than the behavior of those compilers, but still.
Probably the compiler generated the trap code because it didn't
(yet?) know whether foo is ever called. If it were clever enough
to prove that foo is never called, it could generate no code for
it at all.
The note on the definition of undefined behavior is a bit vague.
It permits terminating a translation in response to UB, but that
doesn't address exactly when it can do so. I believe it can do so
only when it can prove that the UB always occurs, but that's not
clearly stated.
However, the behavior of the program as a whole is clearly defined.
It returns a status of 0 from main and does nothing else.
A conforming implementation *must* generate code that implements
that behavior.
Another argument (subject to interpretation of wording): Undefined
behavior is "behavior, **upon use** of a nonportable or erroneous
program construct or of erroneous data, for which this document
imposes no requirements". The overflowing expression within foo()
is never *used*, so there is no undefined behavior.
To put it another way, undefined behavior is behavior. Something
that never occurs is not behavior.
> It is clearly the _intent_ that this be a strictly conforming
> program. The C standard, as an imprecise, informal document,
> cannot guarantee it.
>
>>>>If the usual "Hello, world" program prints "Hello, world" followed
>>>>by "Goodbye", the implementation is non-conforming. If it formats
>>>>my hard drive after printing "Goodbye", it's non-conforming and
>>>>dangerous.
>>>
>>> Two separate things. My point earlier was that code can
>>> obviously run after `main` terminates. Moreoever, I can't
>>> imagine what would _prevent_ a runtime system that invokes
>>> `main` from doing something like printing, "PROGRAM STOPPED"
>>> after `main` returned. C imposes no requirements here.
>>
>>Yes, it does. An OS can print "PROGRAM STOPPED", but not as part
>>of the execution of the program. On my system, a shell prompt is
>>printed after a program terminates, but not by the program. If I
>>execute a "hello, world" program with its output redirected to a file
>>(on a system that supports that), the resulting file cannot contain
>>"PROGRAM STOPPED". The requirements in 5.1.2.4 specify both what
>>the execution of a program must do and what it must not do.
>
> Files are a separate case. There's no guarantee that the
> standard output refers to a file; it may well refer to an
> "interactive device", the semantics of which are (necessarily)
> unspecified.
The requirements for "observable behavior" cover both files and
interactive devices.
> Here's an example: consider an interactive user who uses a
> screen reader device. Suppose that user makes use of an
> implementation that includes runtime support for that device,
> and that precedes invocation of `main` with a command sequence
> causing the screen reader to (perhaps) change intonation; and
> suceeds return from main by outputing another command sequence
> that resets to the original state.
>
> I do not see how C could prohibit that, assuming that the
> implementation takes care to detect whether standard output
> really refers to the screen reader, and does emit the control
> sequences if output is redirected to a file. Another user who
> runs that same program without a screen reader may see the
> standard text printed on the screen, without the control
> sequence sandwich.
>
> I don't think a conforming implementation can prohibit that kind
> of thing.
I agree. printf("hello, world\n") must write that string to standard
output, which may be a file or an interactive device. Just what
that means is unspecified or implementation-defined. It might be
printed in EBCDIC or incised into clay tablets. Closing stdout,
which occurs when main() terminates, might involve firing the tablet
or emitting control sequences for a screen reader.
>>>>>>Whether foo() has external linkage or internal
>>>>>>linkage doesn't change that.
>>>>>
>>>>> I disagree. There's no possible way for the implementation to
>>>>> know whether a function with external linkage will be ultimately
>>>>> invoked or not; consider a system that supports loadable shared
>>>>> modules. Nothing prevents even this simple program from being
>>>>> compiled as a shared module, dynamically loaded, the loading
>>>>> program explicitly searching for and finding the symbol
>>>>> corresponding to the `foo` function, and invoking it.
>>>>
>>>>Remember that linking is translation phase 8. The compiler is not
>>>>the entire implementation.
>>>
>>> Exactly my point. The compiler cannot know how `foo` might be
>>> used, or how the translated object might be exercised. There's
>>> I don't see how it could possibly know that, given that `foo`
>>> has external linkage.
>>
>>We were presented with a complete translation unit that included a
>>function definition for "main". It's a complete program. There's no
>>valid way for some other program to call foo. If OS provided such
>>a mechanism, it would be outside the scope of C.
>
> Given an excessively pedantic and literal reading of the text of
> the standard, I don't think an implementation is explicitly
> prohibited from evaluating the initializer at translation time,
> deducing that the behavior is undefined, and blaming it on the
> program, at which point, all bets are off.
An implementation can certainly evaluate the initializer at
translation time, deduce that the behavior would be undefined
*if the initializer were evaluated*, and blame it on the program.
That doesn't mean it can reject a strictly conforming program.
>>>>> Hence, the compiler _must_ treat with UB as written, which is
>>>>> why `ubsan` inserts trapping code in `foo`.
>>>>
>>>>I don't know what "_must_ treat with UB" means.
>>>>
>>>>foo() has undefined behavior if it's called, so replacing its
>>>>body with trapping code is valid. But (I'm reasonably sure that)
>>>>an implementation cannot reject a program just because it can't
>>>>prove that it has no undefined behavior during execution. It can
>>>>reject it if it can prove that it *always* has undefined behavior
>>>>during execution.
>>>
>>> What I'm saying is that, `foo` has undefined behavior _period_.
>>> That's manifest in an integer constant expression, whether it is
>>> executed at runtime or not. I believe that the standard forces
>>> the expression to be evaluated at translation time, via the
>>> "shall" mandate when checking the constraint on the range in sec
>>> 6.6 para 4. Further, that evaluation must happen in accordance
>>> with the rules of the abstract machine, as per 5.1.2.4 para 17.
>>> The diagnostic is mandated, as is the translation-time
>>> evaluation. The expression is itself manifestly exhibits UB,
>>> and so therefore the result of the rest of the translation is
>>> undefined.
>>
>>foo is a function. foo does not have undefined behavior; it has no
>>behavior at all. A *call* to foo during execution has undefined
>>behavior. (`foo;` is a statement-expression that does nothing;
>>it does not have undefined behavior.)
>
> The _evaluation_ of that expression in `foo` has undefined
> behavior. The standard does not say that it _cannot_ be
> evaluated at translation time.
If a compiler sees a subexpression INT_MAX+1 it can attempt to
evaluate it at compile time. But it can't just blindly add the
values if overflow would cause a fatal trap, crashing the compiler.
That would be a serious compiler bug. The behavior *of the compiler*
is not undefined.
>>[SNIP]
>>
>>I think the question of whether the initializer is a
>>constant-expression or not has caused some not entirely relevant
>>confusion.
>>
>>Here's another example that avoids that issue.
>>
>>#include <limits.h>
>>
>>int foo(void) {
>> int zero;
>> zero = INT_MAX;
>> zero ++;
>> zero *= 0;
>> return zero;
>>}
>>
>>int main(void) {
>> return 0;
>>}
>>
>>Given my grammatical argument above, I would say that this program
>>has no constant expressions.
>
> Agreed, if by "constant expressions" you mean those mandated to
> use the `constant-expression` grammatical production.
Yes, that's what I mean by it.
>>Whether that argument is correct or
>>not, it certainly has no constant expressions that violate any
>>constraint or that have undefined behavior. Evaluating `zero ++`
>>(which doesn't even pretend to be a constant expression) would have
>>run-time undefined behavior -- *if* foo() were ever called.
>
> Let me turn this around in two ways: suppose that the
> translation unit _only_ included `foo`. Could the compiler
> deduce that the behavior of `foo`, if called, is undefined? If
> not, why not?
Certainly.
> Second, suppose that `foo` _were_ called, could the compiler
> replace this with a program that was the equivalent of,
> `int main(void) {printf("check your nose"); abort();}`? If so
> why? If not, why not?
Yes, if foo were called in every possible execution of the program,
the program's behavior would be undefined. The compiler could also
reject it.
>>And given this translation unit, I don't think there's any way to
>>construct a multi-TU program that calls foo, so a compiler *can*
>>determine that foo is never called (but there's no requirement to
>>do so, or to make any use of that information).
>
> This is the crux of my point, as well. There's not requirement
> for the translator to _not_ evaluate the expression and become
> privy to UB.
I believe there is. The program is strictly conforming, which means,
among other things, that it does not produce output depending on any
undefined behavior. There is no undefined behavior because foo() is
never called.
A *strictly conforming program* shall use only those features of the
language and library specified in this document. It shall not
produce output dependent on any unspecified, undefined, or
implementation- defined behavior, and shall not exceed any minimum
implementation limit.
...
A *conforming hosted implementation* shall accept any strictly
conforming program.
An implementation that rejects the program quoted at the top of this
article is non-conforming.
> Would it be stupid if a compiler did that? Yes. Do existing
> compilers do so? No, not that I'm aware of. Would some dweeb
> nerd compiler douche who thinks this would make a compiler
> benchmark some microfraction of a percent faster take advantage
> of that? I absolutely think so, yes.
And I'd submit a bug report.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2026-06-06 15:47 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <86v7bv9thw.fsf@linuxsc.com> |
| In reply to | #399731 |
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes: > I claim that an expression that looks like a constant expression > *isn't* a constant-expression if it doesn't appear in a context > that requires a constant-expression. Right. This question came up years ago in a Defect Report. The response from the Committee was basically the same as what you said: the 6.6 constraints for constant expressions apply only in situations where the C standard expressly requires a constant expression. (I don't have the DR in front of me; I'm summarizing based on memory, but am confident the actual wording is consistent with what I just said.)
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-06 16:36 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <1102ate$25nse$1@kst.eternal-september.org> |
| In reply to | #399772 |
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>> I claim that an expression that looks like a constant expression
>> *isn't* a constant-expression if it doesn't appear in a context
>> that requires a constant-expression.
>
> Right. This question came up years ago in a Defect Report. The
> response from the Committee was basically the same as what you
> said: the 6.6 constraints for constant expressions apply only in
> situations where the C standard expressly requires a constant
> expression. (I don't have the DR in front of me; I'm summarizing
> based on memory, but am confident the actual wording is consistent
> with what I just said.)
C99 DR 261 looks similar to what you're talking about.
https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_261.htm
The Committee Response section says:
In general, the interpretation of an expression for constantness
is context sensitive. For any expression which contains only
constants:
- If the syntax or context only permits a constant expression, the
constraints of 6.6#3 and 6.6#4 shall apply.
- Otherwise, if the expression meets the requirements of 6.6
(including any form accepted in accordance with 6.6#10), it is a
constant expression.
- Otherwise it is not a constant expression.
That's close to what I claimed, but the second bullet point differs.
My claim was that, given:
n = 2+2;
2+2 is not a constant expression because the grammar doesn't require
a constant expression in that context. The Committee's opinion
(at least at the time) was that it is a constant expression because
it meets the requirements of 6.6.
But I *think* it's a distinction without a difference. Calling 2+2
a constant expression has no effect on the semantics, and does not
require or forbid the implementation from, for example, generating
an ADD instruction. The distinction would matter for an expression
that has UB and/or does not yield a value of the type, but that
falls through to the third bullet.
I found another interesting tidbit, C90 DR 031, relevant to another
point I made elsethread:
https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_031.html
case (INT_MAX*4)/4: is a constraint violation.
When subclause 6.4 says on page 55, lines 11-12:
Each constant expression shall evaluate to a constant that is in
the range of representable values for its type.
the Committee's judgement of the intent is that the
``representable'' requirement applies to each subexpression of a
constant expression, as shown in the third example. A constant
expression is meant as defined by the syntax rules.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2026-06-06 16:43 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <86mrx79qva.fsf@linuxsc.com> |
| In reply to | #399776 |
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes: > Tim Rentsch <tr.17687@z991.linuxsc.com> writes: > >> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes: >> >>> I claim that an expression that looks like a constant expression >>> *isn't* a constant-expression if it doesn't appear in a context >>> that requires a constant-expression. >> >> Right. This question came up years ago in a Defect Report. The >> response from the Committee was basically the same as what you >> said: the 6.6 constraints for constant expressions apply only in >> situations where the C standard expressly requires a constant >> expression. (I don't have the DR in front of me; I'm summarizing >> based on memory, but am confident the actual wording is consistent >> with what I just said.) > > C99 DR 261 looks similar to what you're talking about. > > https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_261.htm > > The Committee Response section says: > > In general, the interpretation of an expression for constantness > is context sensitive. For any expression which contains only > constants: > > - If the syntax or context only permits a constant expression, the > constraints of 6.6#3 and 6.6#4 shall apply. > - Otherwise, if the expression meets the requirements of 6.6 > (including any form accepted in accordance with 6.6#10), it is a > constant expression. > - Otherwise it is not a constant expression. > > That's close to what I claimed, but the second bullet point differs. > My claim was that, given: > > n = 2+2; > > 2+2 is not a constant expression because the grammar doesn't require > a constant expression in that context. The Committee's opinion > (at least at the time) was that it is a constant expression because > it meets the requirements of 6.6. > > But I *think* it's a distinction without a difference. [...] Right. The key point is that the constraints need to be satisfied only in situations where the C standard expressly requires a constant expression. Whether a given expression is called a "constant expression" doesn't matter; all that does matter is whether the constraints need to be satisfied.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-06 17:41 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <1102enu$26qtr$1@kst.eternal-september.org> |
| In reply to | #399777 |
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
[...]
>> That's close to what I claimed, but the second bullet point differs.
>> My claim was that, given:
>>
>> n = 2+2;
>>
>> 2+2 is not a constant expression because the grammar doesn't require
>> a constant expression in that context. The Committee's opinion
>> (at least at the time) was that it is a constant expression because
>> it meets the requirements of 6.6.
>>
>> But I *think* it's a distinction without a difference. [...]
>
> Right. The key point is that the constraints need to be satisfied
> only in situations where the C standard expressly requires a
> constant expression. Whether a given expression is called a
> "constant expression" doesn't matter; all that does matter is
> whether the constraints need to be satisfied.
Well, it matters a little bit, at least to me, even though the
distinction doesn't seem to affect the validity or semantics of
any C code.
A clear and unambiguous definition of what is or is not a "constant
expression" would make the language just a bit easier to understand
and explain. I'd even be satisified with the definition given in
the DR *if* it were clearly expressed in the standard.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Janis Papanagnou <janis_papanagnou+ng@hotmail.com> |
|---|---|
| Date | 2026-06-05 10:41 +0200 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vu236$fm4o$4@dont-email.me> |
| In reply to | #399725 |
On 2026-06-05 01:49, Dan Cross wrote: >> [...] > [...] > [ ... (INT_MAX+1)*0 ] > Furthermore, the expression above is obviously an integer > constant expression as defined by sec 6.6 para 8. Section 6.6, > para 4, reads in part, "Each constant expression shall evaluate > to a constant that is in the range of representable values for > its type." The expression, `(INT_MAX+1)*0` violates this > constraint, and so therefore a diagnostic is mandated as per > sec 5.1.1.3 para 1. That it appears in code that is not > obviously called from `main` doesn't change that. I'm curious about that "violation"; a violation would require (at least) two sorts of logical preconditions. - The first is that all *sequentially* (literally) evaluated sub-expression values are representable as value - INT_MAX+1 certainly can't be represented in generated code that conforms to the abstract *mathematical* value - but is that necessary if _the whole_ expression is (mathematically) just 0 (because of the final factor). And the second (related) is whether the order of the sub-expression evaluation is relevant; if we'd assume the expression evaluation to be considered from right to left then it would be irrelevant what's inside the parenthesis. From the standard quotes I cannot really recognize that these preconditions, how to determine UB/errors/violations, would be necessary. I'm no native speaker and I fear my question as formulated was hard to understand. It's basically the question of the standard implying (INT_MAX+1)*0 to be analyzed sequentially as written or whether it could as well analyze it from right to left and thus recognizing no problem, since from the mathematical view - but also practically - a concrete representable value of a here irrelevant sub-expression isn't necessary. Or another try of a (paraphrased) formulation; for the determination of constraint violations does the expression have strict (sort of) sequencing points _after each term_ (and each left-to-right sub-expression has to be well-defined) or can it be valued/analyzed as a whole not putting any preconditions about evaluation order etc. when determining the overall value? Janis PS: One yet non-considered question that was part of my original post was: "Is there any rationale from the _software designer_'s perspective?" > [...]
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-05 10:49 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vv27c$1aoa2$1@kst.eternal-september.org> |
| In reply to | #399741 |
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
> On 2026-06-05 01:49, Dan Cross wrote:
>>> [...]
>> [...]
>
>> [ ... (INT_MAX+1)*0 ]
>
>> Furthermore, the expression above is obviously an integer
>> constant expression as defined by sec 6.6 para 8. Section 6.6,
>> para 4, reads in part, "Each constant expression shall evaluate
>> to a constant that is in the range of representable values for
>> its type." The expression, `(INT_MAX+1)*0` violates this
>> constraint, and so therefore a diagnostic is mandated as per
>> sec 5.1.1.3 para 1. That it appears in code that is not
>> obviously called from `main` doesn't change that.
>
> I'm curious about that "violation"; a violation would require
> (at least) two sorts of logical preconditions. - The first is
> that all *sequentially* (literally) evaluated sub-expression
> values are representable as value - INT_MAX+1 certainly can't
> be represented in generated code that conforms to the abstract
> *mathematical* value - but is that necessary if _the whole_
> expression is (mathematically) just 0 (because of the final
> factor). And the second (related) is whether the order of the
> sub-expression evaluation is relevant; if we'd assume the
> expression evaluation to be considered from right to left then
> it would be irrelevant what's inside the parenthesis.
If the expression were evaluated right to left, it would still
compute INT_MAX+1, which is UB.
Let's look at an example where it's not in a context that requires a
constant expression:
int n;
n = (INT_MAX+1)*0;
In the abstract machine, the RHS is evaluated by adding INT_MAX
and 1 (which overflows, UB) and then multiplying the result by 0.
A compiler is allowed, but not required, to reduce the assignment to
`n = 0;`. If it does so, then no overflow occurs at run time --
but the definedness of the behavior is determined independent of
any optimizations. The C standard does not require any particular
behavior. It can set n to 0 because that's a valid consequence
of UB.
Let's take an example where it's definitely in a context that
requires an integer constant expression:
switch (0) {
case (INT_MAX+1)*0:
break;
}
The wording in 6.6 (Constant expressions) is slightly vague.
For example, I would assume that any subexpression of a constant
expression must be a constant expression, but it doesn't actually
say so.
But since, in the abstract machine, (INT_MAX+1)*0 doesn't yield
any defined value, I'd say it violates the constraint that "Each
constant expression shall evaluate to a constant that is in the
range of representable values for its type".
The alternative would be for to be a constant expression for
implementations that are able to recognize that anything multiplied
by zero is zero (analysis that compilers aren't required to perform),
and not for others.
On the other hand, "An implementation may accept other forms of
constant expressions; however, it is implementation-defined whether
they are an integer constant expression." That probably allows,
but does not reuqire, an implementation to treat (INT_MAX+1)*0 as
a constant expression with the value 0.
> From the standard quotes I cannot really recognize that these
> preconditions, how to determine UB/errors/violations, would be
> necessary.
>
> I'm no native speaker and I fear my question as formulated was
> hard to understand. It's basically the question of the standard
> implying (INT_MAX+1)*0 to be analyzed sequentially as written
> or whether it could as well analyze it from right to left and
> thus recognizing no problem, since from the mathematical view -
> but also practically - a concrete representable value of a here
> irrelevant sub-expression isn't necessary. Or another try of a
> (paraphrased) formulation; for the determination of constraint
> violations does the expression have strict (sort of) sequencing
> points _after each term_ (and each left-to-right sub-expression
> has to be well-defined) or can it be valued/analyzed as a whole
> not putting any preconditions about evaluation order etc. when
> determining the overall value?
>
> PS: One yet non-considered question that was part of my original
> post was: "Is there any rationale from the _software designer_'s
> perspective?"
From a programmer's perspective, it's good to have consistent
rules rather than leaving the decision of whether an expression
is a constant expression up to the undocumented vagaries of how
clever a compiler happens to be.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2026-06-06 16:15 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <86qzmj9s7a.fsf@linuxsc.com> |
| In reply to | #399741 |
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
> PS: One yet non-considered question that was part of my original
> post was: "Is there any rationale from the _software designer_'s
> perspective?"
I didn't respond to your original question because it was based on a
misconception. Whether a given expression is a constant expression,
in the sense of needing to satisfy the constraints of 6.6, depends
not on the form of the expression but on the context in which it
appears. The 6.6 constraints apply only in situations where the C
standard expressly requires a constant expression. Other cases,
such as a use like this
int
whatever(){
int r = (int)(-1u/2) + 1;
return r;
}
do not need to satisfy the 6.6 constraints, because the C standard
doesn't require a constant expression in that context. (Note that
the initializing expression for 'r' does overflow the range of int
in implementations where UINT_MAX == INT_MAX*2.)
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2026-06-06 18:06 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <86ik7v9n1e.fsf@linuxsc.com> |
| In reply to | #399710 |
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
> cross@spitfire.i.gajendra.net (Dan Cross) writes:
>
>> In article <865x3yd21n.fsf@linuxsc.com>,
>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>
>>> cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>
>>>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>
> [...]
>
>>>>> There's an important distinction to make here. Consider this
>>>>> program:
>>>>>
>>>>> #include <limits.h>
>>>>>
>>>>> int
>>>>> foo(){
>>>>> int zero = (INT_MAX+1)*0;
>>>>> return zero;
>>>>> }
>>>>>
>>>>> int
>>>>> main(){
>>>>> return 0;
>>>>> }
>>>>>
>>>>> This program does not transgress the bounds of undefined behavior.
>>>
>>> To clarify, the comments in my posting were meant to be read as
>>> saying the given text is the entire program, and that it is strictly
>>> conforming with respect to conforming hosted implementations.
>>> (Incidentally, given the rules for freestanding implementations, I'm
>>> not sure that it is even possible for any program to be strictly
>>> conforming with respect to conforming freestanding implementations.
>>> In any case my statements were meant only in the context of hosted
>>> implementations.)
[...]
> foo() has undefined behavior if it's called, so replacing its
> body with trapping code is valid.
Right.
> But (I'm reasonably sure that)
> an implementation cannot reject a program just because it can't
> prove that it has no undefined behavior during execution. [...]
Right.
>> In your example, `foo` clearly exhibits UB; I think your
>> argument is whether that has a realized effect or not, since the
>> UB is not invoked. I'm saying that in general a compiler cannot
>> possibly know that when it compiles `foo`, and is free to assume
>> the worst.
>
> foo() exhibits UB if and only if it's called during execution.
Right.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-02 05:35 -0700 |
| Message-ID | <10vmimv$2tjoi$3@kst.eternal-september.org> |
| In reply to | #399608 |
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
> On 2026-06-01 00:54, Keith Thompson wrote:
>>> [...]
>> Yes, a compiler can reduce (a + b) * 0 to just 0. But it's not
>> required to do so, and (INT_MAX + 1) * 0 still has undefined
>> behavior. Undefined behavior is determined by the rules of the
>> abstract machine *without* any adjustments permitted by the as-if
>> rule.
>
> This is something I really don't get in the actual C-logic...
>
> Using constants that can be determined at compile time is UB here,
> despite the '* 0' mathematically indicating an IMO clear semantics,
> but using variables is only UB possibly at runtime? And despite all
> that the latter might not even get triggered because it's probably
> optimized away? - I can't help, this sounds really crude.
>
> Is there any rationale from the _software designer_'s perspective?
In the abstract machine, every operator and subexpression is
evaluated (barring things like "||", "&&", and "?:"). (INT_MAX + 1)
has undefined behavior due to overflow, therefore any expression
that has (INT_MAX + 1) as a subexpression has undefined behavior.
Replacing (expr * 0) by 0 is an optimization, and optimizations
are *optional*. A naive implementation could generate code that
peforms the addition and the muliplication by 0; if the addition
traps, it traps.
Note that in a context that requires a constant expression, overflow is
a constraint violation. For example, a case label like:
case (INT_MAX + 1) * 0:
must be diagnosed at compile time.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2026-06-02 06:29 -0700 |
| Message-ID | <86ecipcbqa.fsf@linuxsc.com> |
| In reply to | #399618 |
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes: > Note that in a context that requires a constant expression, overflow is > a constraint violation. For example, a case label like: > > case (INT_MAX + 1) * 0: > > must be diagnosed at compile time. gcc disagrees with you.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2026-06-02 16:10 +0200 |
| Message-ID | <10vmo8n$2ruaa$3@dont-email.me> |
| In reply to | #399625 |
On 02/06/2026 15:29, Tim Rentsch wrote: > Keith Thompson <Keith.S.Thompson+u@gmail.com> writes: > >> Note that in a context that requires a constant expression, overflow is >> a constraint violation. For example, a case label like: >> >> case (INT_MAX + 1) * 0: >> >> must be diagnosed at compile time. > > gcc disagrees with you. My testing shows all versions of gcc that I tested on godbolt gave a warning, even without any options. I don't believe that INT_MAX can have any type suffixes that would avoid the overflow. What version of gcc and/or flags let that case label pass without a diagnostic? (I don't know if Keith is correct about it being a constraint violation - I have not looked at the details there.)
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-02 15:29 -0700 |
| Message-ID | <10vnlgu$382un$2@kst.eternal-september.org> |
| In reply to | #399625 |
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>> Note that in a context that requires a constant expression, overflow is
>> a constraint violation. For example, a case label like:
>>
>> case (INT_MAX + 1) * 0:
>>
>> must be diagnosed at compile time.
>
> gcc disagrees with you.
What makes you think so?
$ cat c.c
#include <limits.h>
int main(void) {
switch (0) {
case (INT_MAX + 1) * 0:
break;
}
}
$ gcc -std=c17 -pedantic-errors -c c.c
c.c: In function ‘main’:
c.c:4:23: warning: integer overflow in expression of type ‘int’ results in ‘-2147483648’ [-Woverflow]
4 | case (INT_MAX + 1) * 0:
| ^
c.c:4:9: error: overflow in constant expression [-Woverflow]
4 | case (INT_MAX + 1) * 0:
| ^~~~
$
But taking a closer look at the standard, I'm not 100% sure that the
language requires a diagnostic, though I think that's the intent.
The relevant constraint is:
Each constant expression shall evaluate to a constant that is
in the range of representable values for its type.
If I squint really hard, I can argue that the entire expression
has to be a constant expression, but it doesn't say that its
subexpressions are constant expressions -- and *if* INT_MAX +
1 evaluates to INT_MIN in the current implementation, then
(INT_MAX + 1) * 0 evaluates to 0 and therefore satisfies the
constraint.
But INT_MAX + 1 could legally trap, for example, and I don't believe
it was intended that a given expression can be a constant expression
or not depending on the vagaries of the behavior of an instance
of UB.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
Page 5 of 14 — ← Prev page 1 … 3 4 [5] 6 7 … 14 Next page →
Back to top | Article view | comp.lang.c
csiph-web