Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #147447 > unrolled thread
| Started by | DFS <nospam@dfs.com> |
|---|---|
| First post | 2019-11-01 08:42 -0400 |
| Last post | 2019-11-01 23:19 +0000 |
| Articles | 20 on this page of 88 — 19 participants |
Back to article view | Back to comp.lang.c
memcpy not memcpying? DFS <nospam@dfs.com> - 2019-11-01 08:42 -0400
Re: memcpy not memcpying? DFS <nospam@dfs.com> - 2019-11-01 08:49 -0400
Re: memcpy not memcpying? James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-11-01 09:24 -0400
Re: memcpy not memcpying? DFS <nospam@dfs.com> - 2019-11-01 09:46 -0400
Re: memcpy not memcpying? James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-11-01 09:49 -0400
Re: memcpy not memcpying? Keith Thompson <kst-u@mib.org> - 2019-11-01 10:19 -0700
Re: memcpy not memcpying? David Brown <david.brown@hesbynett.no> - 2019-11-01 21:14 +0100
Re: memcpy not memcpying? DFS <nospam@dfs.com> - 2019-11-01 17:16 -0400
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-01 22:42 +0000
Re: memcpy not memcpying? Richard Damon <Richard@Damon-Family.org> - 2019-11-01 21:10 -0400
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-02 11:36 +0000
Re: memcpy not memcpying? Keith Thompson <kst-u@mib.org> - 2019-11-02 02:15 -0700
Re: memcpy not memcpying? David Brown <david.brown@hesbynett.no> - 2019-11-02 13:04 +0100
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-02 13:43 +0000
Re: memcpy not memcpying? David Brown <david.brown@hesbynett.no> - 2019-11-02 17:24 +0100
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-02 17:00 +0000
Re: memcpy not memcpying? Keith Thompson <kst-u@mib.org> - 2019-11-02 13:06 -0700
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-02 21:05 +0000
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-02 22:40 +0000
Re: memcpy not memcpying? Keith Thompson <kst-u@mib.org> - 2019-11-02 15:59 -0700
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-02 23:47 +0000
Re: memcpy not memcpying? Keith Thompson <kst-u@mib.org> - 2019-11-02 18:22 -0700
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-03 13:27 +0000
Re: memcpy not memcpying? David Brown <david.brown@hesbynett.no> - 2019-11-03 17:46 +0100
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-03 17:20 +0000
Re: memcpy not memcpying? Manfred <noname@add.invalid> - 2019-11-03 19:44 +0100
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-03 19:36 +0000
Re: memcpy not memcpying? Manfred <noname@add.invalid> - 2019-11-03 22:57 +0100
Re: memcpy not memcpying? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-11-03 22:39 +0000
Re: memcpy not memcpying? David Brown <david.brown@hesbynett.no> - 2019-11-03 23:06 +0100
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-03 23:28 +0000
Re: memcpy not memcpying? David Brown <david.brown@hesbynett.no> - 2019-11-04 11:00 +0100
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-04 11:14 +0000
Re: memcpy not memcpying? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-11-04 11:22 +0000
Re: memcpy not memcpying? David Brown <david.brown@hesbynett.no> - 2019-11-04 13:10 +0100
Re: memcpy not memcpying? Keith Thompson <kst-u@mib.org> - 2019-11-04 10:03 -0800
Re: memcpy not memcpying? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-11-04 19:36 +0000
Re: memcpy not memcpying? Keith Thompson <kst-u@mib.org> - 2019-11-05 10:04 -0800
Re: memcpy not memcpying? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-11-04 20:58 -0800
Re: memcpy not memcpying? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-11-04 22:01 -0800
Re: memcpy not memcpying? Autist <autist69@gmail.com> - 2019-11-04 12:56 +0100
Re: memcpy not memcpying? James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-11-04 09:50 -0500
Re: memcpy not memcpying? scott@slp53.sl.home (Scott Lurndal) - 2019-11-04 20:26 +0000
Re: memcpy not memcpying? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-11-04 04:34 -0800
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-04 13:05 +0000
Re: memcpy not memcpying? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-11-04 14:09 +0000
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-04 15:11 +0000
Re: memcpy not memcpying? Melzzzzz <Melzzzzz@zzzzz.com> - 2019-11-04 15:15 +0000
Re: memcpy not memcpying? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-11-04 15:43 +0000
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-03 20:20 +0000
Re: memcpy not memcpying? Ian Collins <ian-news@hotmail.com> - 2019-11-03 14:37 +1300
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-03 11:01 +0000
Re: memcpy not memcpying? Öö Tiib <ootiib@hot.ee> - 2019-11-03 04:03 -0800
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-03 12:52 +0000
Re: memcpy not memcpying? Öö Tiib <ootiib@hot.ee> - 2019-11-03 23:34 -0800
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-04 09:36 +0000
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-04 16:20 +0000
Re: memcpy not memcpying? Ian Collins <ian-news@hotmail.com> - 2019-11-04 07:46 +1300
Re: memcpy not memcpying? Keith Thompson <kst-u@mib.org> - 2019-11-03 12:26 -0800
Re: memcpy not memcpying? David Brown <david.brown@hesbynett.no> - 2019-11-03 17:31 +0100
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-03 17:05 +0000
Re: memcpy not memcpying? already5chosen@yahoo.com - 2019-11-03 09:14 -0800
Re: memcpy not memcpying? Keith Thompson <kst-u@mib.org> - 2019-11-03 12:32 -0800
Re: memcpy not memcpying? already5chosen@yahoo.com - 2019-11-03 14:59 -0800
Re: memcpy not memcpying? already5chosen@yahoo.com - 2019-11-03 15:19 -0800
Re: memcpy not memcpying? already5chosen@yahoo.com - 2019-11-03 17:00 -0800
Re: memcpy not memcpying? DFS <nospam@dfs.com> - 2019-11-02 11:16 -0400
Re: memcpy not memcpying? David Brown <david.brown@hesbynett.no> - 2019-11-02 17:26 +0100
Re: memcpy not memcpying? Barry Schwarz <schwarzb@delq.com> - 2019-11-01 06:39 -0700
Re: memcpy not memcpying? DFS <nospam@dfs.com> - 2019-11-01 09:56 -0400
Re: memcpy not memcpying? Barry Schwarz <schwarzb@delq.com> - 2019-11-01 12:39 -0700
Re: memcpy not memcpying? guinness.tony@gmail.com - 2019-11-01 06:49 -0700
Re: memcpy not memcpying? jak <nospam@please.ty> - 2019-11-01 20:40 +0100
Re: memcpy not memcpying? Autist <autist69@gmail.com> - 2019-11-01 14:26 +0100
Re: memcpy not memcpying? Keith Thompson <kst-u@mib.org> - 2019-11-01 10:22 -0700
Re: memcpy not memcpying? Bart <bc@freeuk.com> - 2019-11-01 19:44 +0000
Re: memcpy not memcpying? Autist <autist69@gmail.com> - 2019-11-01 21:31 +0100
Re: memcpy not memcpying? James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-11-01 09:39 -0400
Re: memcpy not memcpying? Autist <autist69@gmail.com> - 2019-11-01 14:42 +0100
Re: memcpy not memcpying? James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-11-01 09:48 -0400
Re: memcpy not memcpying? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-11-01 06:47 -0700
Re: memcpy not memcpying? Autist <autist69@gmail.com> - 2019-11-01 14:58 +0100
Re: memcpy not memcpying? DFS <nospam@dfs.com> - 2019-11-01 10:22 -0400
Re: memcpy not memcpying? Autist <autist69@gmail.com> - 2019-11-01 18:38 +0100
Re: memcpy not memcpying? scott@slp53.sl.home (Scott Lurndal) - 2019-11-01 17:54 +0000
Re: memcpy not memcpying? Autist <autist69@gmail.com> - 2019-11-01 20:24 +0100
Re: memcpy not memcpying? DFS <nospam@dfs.com> - 2019-11-01 15:24 -0400
Re: memcpy not memcpying? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-11-01 23:19 +0000
Page 2 of 5 — ← Prev page 1 [2] 3 4 5 Next page →
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-11-02 23:47 +0000 |
| Message-ID | <EAovF.246198$IsL.142854@fx08.am4> |
| In reply to | #147519 |
On 02/11/2019 22:59, Keith Thompson wrote:
> Bart <bc@freeuk.com> writes:
> And yet you continue to whine about it. Have fun with that.
David Brown was trying to put the blame for the non-support of zu on
tcc, for which he has demonstrated a very poor opinion.
I'm pointing out that my 500x bigger gcc installation has exactly same
problem.
> Earlier today, I installed MinGW-w64. "%zu" worked correctly.
> If you don't care why, I certainly don't.
That's nice. But I'm not prepared to trawl through my 26,000 files (for
tdm and mingw64) to try to figure what's going on. That's not my job.
I tell gcc - and its bundled headers, assembler, linkers and what-not -
that I want to call printf("%zu",sizeof(T)), it's its job to make it work.
> <stdint.h> defines a large number of integer types. Defining printf and
> scanf formats for *all* of them would, I think, have been an undue
> burden.
MS libraries support I64 and I32 width specifiers (as in "%I64d"). That
wouldn't have been a bad starting point.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-11-02 18:22 -0700 |
| Message-ID | <lnv9s169ev.fsf@kst-u.example.com> |
| In reply to | #147520 |
Bart <bc@freeuk.com> writes:
> On 02/11/2019 22:59, Keith Thompson wrote:
>> Bart <bc@freeuk.com> writes:
>
>> And yet you continue to whine about it. Have fun with that.
>
> David Brown was trying to put the blame for the non-support of zu on
> tcc, for which he has demonstrated a very poor opinion.
He was not. He was pointing out, quite correctly, that supporting
"%zu" is not tcc's job any more than it's gcc's job. The problem
is in the runtime library that's part of whatever implementation
you're using that includes tcc as its compiler component.
> I'm pointing out that my 500x bigger gcc installation has exactly same
> problem.
Yes, I understood that the first time you said it. Your 500x bigger
installation is using a C library that doesn't support "%zu".
>> Earlier today, I installed MinGW-w64. "%zu" worked correctly.
>> If you don't care why, I certainly don't.
>
> That's nice. But I'm not prepared to trawl through my 26,000 files (for
> tdm and mingw64) to try to figure what's going on. That's not my job.
Was I unclear? Nobody is asking you to trawl through anything.
You've said you don't care, and I'm not even saying you should.
> I tell gcc - and its bundled headers, assembler, linkers and what-not -
> that I want to call printf("%zu",sizeof(T)), it's its job to make it work.
Bart, you know what "gcc" is. And again, you've already said you
don't care why "%zu" doesn't work for you. Someone who really
didn't care would have stopped talking about it by now.
>> <stdint.h> defines a large number of integer types. Defining printf and
>> scanf formats for *all* of them would, I think, have been an undue
>> burden.
>
> MS libraries support I64 and I32 width specifiers (as in "%I64d"). That
> wouldn't have been a bad starting point.
Maybe -- but the MS libraries can assume that the implementation
supports integer types of exactly 32 and 64 bits. The C standard
does not make that assumption. For example, <inttypes.h>
defines macros PRId32, PRIdLEAST32, and PRIdFAST32 for int32_t,
int_least32_t, and int_fast32_t, respectively. The type int32_t is
optional; int_least32_t and int_fast32_t are mandatory. The standard
has to cover more possible target systems than Windows does (or
Linux, or POSIX), including systems that may not exist yet.
You can see a list of the macros in N1570 7.8.1. Some of them
exist for each width, at least 8, 16, 32, and 64, for a total
of 84 PRI* macros and 70 SCN* macros if I've counted correctly.
(Exotic implementations might support other widths, or might
not support all of 8, 16, 32, and 64 for the exact-width types.)
You *could* implement those 154 possibilities directly in the *printf
and *scanf functions, with distinct syntaxes in the format strings,
but I prefer the way it's done in the standard.
I'm not saying that the PRI* and SCN* macros are ideal, but I
can't think of a cleaner way to define them while supporting the
same functionality. No doubt your private language does it better,
but that doesn't help C.
(I've just noticed that there are macros for the [u]intmax_t types,
which are redundant with the 'j' length modifier. I don't think that
redundancy is a problem.)
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-11-03 13:27 +0000 |
| Message-ID | <1BAvF.13970$mB7.12243@fx32.am4> |
| In reply to | #147521 |
On 03/11/2019 01:22, Keith Thompson wrote: > Bart <bc@freeuk.com> writes: >> MS libraries support I64 and I32 width specifiers (as in "%I64d"). That >> wouldn't have been a bad starting point. > > Maybe -- but the MS libraries can assume that the implementation > supports integer types of exactly 32 and 64 bits. The C standard > does not make that assumption. For example, <inttypes.h> inttypes.h/stdint.h defines int32_t, int64_t etc for which I32, I64 etc would have been far better solutions to the print problem than those ugly PRI32d macros. Of course, it would require additional support within printf implementations, but so did %zu. > defines macros PRId32, PRIdLEAST32, and PRIdFAST32 for int32_t, > int_least32_t, and int_fast32_t, respectively. The type int32_t is > optional; int_least32_t and int_fast32_t are mandatory. The standard > has to cover more possible target systems than Windows does (or > Linux, or POSIX), including systems that may not exist yet. Then it would have been reasonable to mandate I64 support only for systems where int64_t exists. > You can see a list of the macros in N1570 7.8.1. Some of them > exist for each width, at least 8, 16, 32, and 64, for a total > of 84 PRI* macros and 70 SCN* macros if I've counted correctly. > (Exotic implementations might support other widths, or might > not support all of 8, 16, 32, and 64 for the exact-width types.) > You *could* implement those 154 possibilities directly in the *printf > and *scanf functions, with distinct syntaxes in the format strings, > but I prefer the way it's done in the standard. > > I'm not saying that the PRI* and SCN* macros are ideal, but I > can't think of a cleaner way to define them while supporting the > same functionality. No doubt your private language does it better, > but that doesn't help C. I suggested a format "%?" where the compiler fills in the default type where the format string is visible. Which is nearly always. But because it's not perfect, conventional format codes would still be needed. (My implementation of %? was just a proof-of-concept and is not complete, but it's an enhancement I've kept as it is genuinely handy, even if limited to one compiler. (I haven't done field widths, or allowed for X or c interpretations of an int, or forcing signed to unsigned and vice versa, or selecting different kinds of float formats etc etc. But these can be accommodated. The important thing is to have a format where you don't need to know the exact type of the thing being printed, just whether it's int, float, string or pointer. Or, very often, not even that - just print X, whatever type it happens to be, or print X with a given width.))
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-11-03 17:46 +0100 |
| Message-ID | <qpn0a2$dn3$1@dont-email.me> |
| In reply to | #147536 |
On 03/11/2019 14:27, Bart wrote: > On 03/11/2019 01:22, Keith Thompson wrote: >> Bart <bc@freeuk.com> writes: > >>> MS libraries support I64 and I32 width specifiers (as in "%I64d"). That >>> wouldn't have been a bad starting point. >> >> Maybe -- but the MS libraries can assume that the implementation >> supports integer types of exactly 32 and 64 bits. The C standard >> does not make that assumption. For example, <inttypes.h> > > > inttypes.h/stdint.h defines int32_t, int64_t etc for which I32, I64 etc > would have been far better solutions to the print problem than those > ugly PRI32d macros. What would you have used for int_fast32_t, int_least32_t, etc.? (I don't disagree with you that it would have been nice with non-macro format specifiers for the common cases.) > > Of course, it would require additional support within printf > implementations, but so did %zu. > >> defines macros PRId32, PRIdLEAST32, and PRIdFAST32 for int32_t, >> int_least32_t, and int_fast32_t, respectively. The type int32_t is >> optional; int_least32_t and int_fast32_t are mandatory. The standard >> has to cover more possible target systems than Windows does (or >> Linux, or POSIX), including systems that may not exist yet. > > Then it would have been reasonable to mandate I64 support only for > systems where int64_t exists. That is fair enough. > >> You can see a list of the macros in N1570 7.8.1. Some of them >> exist for each width, at least 8, 16, 32, and 64, for a total >> of 84 PRI* macros and 70 SCN* macros if I've counted correctly. >> (Exotic implementations might support other widths, or might >> not support all of 8, 16, 32, and 64 for the exact-width types.) >> You *could* implement those 154 possibilities directly in the *printf >> and *scanf functions, with distinct syntaxes in the format strings, >> but I prefer the way it's done in the standard. >> >> I'm not saying that the PRI* and SCN* macros are ideal, but I >> can't think of a cleaner way to define them while supporting the >> same functionality. No doubt your private language does it better, >> but that doesn't help C. > > I suggested a format "%?" where the compiler fills in the default type > where the format string is visible. Which is nearly always. That opens a range of complications. What should happen when the format string is not a string literal? In internationalised programs, it is common for the format string to be the result of a table lookup. (As an aside, the POSIX positional arguments in printf are a big benefit here - it's a shame they are not in the C standard.) > > But because it's not perfect, conventional format codes would still be > needed. > > (My implementation of %? was just a proof-of-concept and is not > complete, but it's an enhancement I've kept as it is genuinely handy, > even if limited to one compiler. > > (I haven't done field widths, or allowed for X or c interpretations of > an int, or forcing signed to unsigned and vice versa, or selecting > different kinds of float formats etc etc. But these can be accommodated. > > The important thing is to have a format where you don't need to know the > exact type of the thing being printed, just whether it's int, float, > string or pointer. Or, very often, not even that - just print X, > whatever type it happens to be, or print X with a given width.)) > I usually know the type of my variables and expressions, so don't see that as an important thing at all. I /do/, however, agree that the PRI macros are ugly, even though I understand why they exist.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-11-03 17:20 +0000 |
| Message-ID | <%%DvF.115593$Yl3.480@fx24.am4> |
| In reply to | #147543 |
On 03/11/2019 16:46, David Brown wrote:
> On 03/11/2019 14:27, Bart wrote:
>> The important thing is to have a format where you don't need to know
>> the exact type of the thing being printed, just whether it's int,
>> float, string or pointer. Or, very often, not even that - just print
>> X, whatever type it happens to be, or print X with a given width.))
>>
>
> I usually know the type of my variables and expressions, so don't see
> that as an important thing at all. I /do/, however, agree that the PRI
> macros are ugly, even though I understand why they exist.
(1) A numeric type T exported from a library's header. You want to print
it, but now you have to delve into the header to find out what type
it is, to work out what format it needs.
(Using an IDE to find that is not a solution: see (2).)
(2) Even when you know exactly the type T of an expression, you will be
embedding the format string in dozens or hundred of sites within the
code. Then T changes (eg. the library which exports T is updated.)
(3) You define a type like this:
#if cond
int x;
#elif
double x;
#endif
Now you want print x; what format to use?
(4) You have X of type T, and Y of type U, both compatible numeric
types. Now you want to print the value of this expression:
X*Y
What format to use? What about when it changes to X*2+Y*3?. How
about when the expression is complex that you don't know whether the
type is int or double or unsigned long long int?
The "%?" suggestion works with all of these when the type is numeric,
and in many cases also when the type is a pointer or string.
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2019-11-03 19:44 +0100 |
| Message-ID | <qpn76m$mt6$1@gioia.aioe.org> |
| In reply to | #147546 |
On 11/3/2019 6:20 PM, Bart wrote: > On 03/11/2019 16:46, David Brown wrote: >> On 03/11/2019 14:27, Bart wrote: > >>> The important thing is to have a format where you don't need to know >>> the exact type of the thing being printed, just whether it's int, >>> float, string or pointer. Or, very often, not even that - just print >>> X, whatever type it happens to be, or print X with a given width.)) >>> >> >> I usually know the type of my variables and expressions, so don't see >> that as an important thing at all. I /do/, however, agree that the >> PRI macros are ugly, even though I understand why they exist. > > (1) A numeric type T exported from a library's header. You want to print > it, but now you have to delve into the header to find out what type > it is, to work out what format it needs. > > (Using an IDE to find that is not a solution: see (2).) This is a complication, but I would say that if this output is part of the characteristic program output (i.e. it is part of the results that your program is meant to produce) then in a real world case I would be unlikely to directly print some deep library-exported value, the result of my program would probably be some value that is built by my code - so of a type that I know. (Debug output is a different matter, but so is the required API friendliness in this case) > > (2) Even when you know exactly the type T of an expression, you will be > embedding the format string in dozens or hundred of sites within the > code. Then T changes (eg. the library which exports T is updated.) > > (3) You define a type like this: > > #if cond > int x; > #elif > double x; > #endif > > > Now you want print x; what format to use? > > (4) You have X of type T, and Y of type U, both compatible numeric > types. Now you want to print the value of this expression: > > X*Y > > What format to use? What about when it changes to X*2+Y*3?. How > about when the expression is complex that you don't know whether the > type is int or double or unsigned long long int? As an answer, if you know the range of the value, the easiest solution is to cast to the wider type (e.g. double in this case) and format accordingly. However, to me it is fairly well known that printf is not meant to be a complete output engine, so it is no surprise that it is less than friendly when it comes to composing complex output. After all, it is for this reason that most other languages (starting from C++) have tried hard to improve on it - with mixed results by the way. I believe it is fair to say that that C does not aim to be friendly at building elaborated UIs, so if some fancy user output is needed, probably C is not the right tool for the job. The power of the language lies elsewhere. > > > The "%?" suggestion works with all of these when the type is numeric, > and in many cases also when the type is a pointer or string. If I understand it correctly (unless you are suggesting that the compiler would modify the format string), this would require runtime type handling (and in fact several interpreted languages do something very similar today), which may work well with your interpreted language, but not in C.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-11-03 19:36 +0000 |
| Message-ID | <2%FvF.74371$NI41.27093@fx12.am4> |
| In reply to | #147548 |
On 03/11/2019 18:44, Manfred wrote: > On 11/3/2019 6:20 PM, Bart wrote: >> The "%?" suggestion works with all of these when the type is numeric, >> and in many cases also when the type is a pointer or string. > > If I understand it correctly (unless you are suggesting that the > compiler would modify the format string), Yes, this requires the compiler modifying the string. Since the compiler will always know the exact types being printed, it is in the best position to know the default format codes needed. But it can only do this when (a) the format string is visible (ie. a string constant) and (b) when directly calling a *printf function. > this would require runtime > type handling (and in fact several interpreted languages do something > very similar today), which may work well with your interpreted language, > but not in C. Non-interpreted languages are also capable of printing without needing to tell the compiler what it already knows. At least the ones that haven't inherited C's printf. Apart from C, I've only known Fortran have that requirement, and that dates from the 1950s. I'd been coding for over 15 years before I came across C's funny way of printing.
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2019-11-03 22:57 +0100 |
| Message-ID | <qpnigq$evh$1@gioia.aioe.org> |
| In reply to | #147551 |
On 11/3/2019 8:36 PM, Bart wrote: > On 03/11/2019 18:44, Manfred wrote: >> On 11/3/2019 6:20 PM, Bart wrote: > >>> The "%?" suggestion works with all of these when the type is numeric, >>> and in many cases also when the type is a pointer or string. >> >> If I understand it correctly (unless you are suggesting that the >> compiler would modify the format string), > > Yes, this requires the compiler modifying the string. Since the compiler > will always know the exact types being printed, it is in the best > position to know the default format codes needed. > > But it can only do this when (a) the format string is visible (ie. a > string constant) and (b) when directly calling a *printf function. More importantly it would be a major break of how the language handles strings (and data in general): when the programmer writes "abc" this translates into a specific data layout in memory which has a direct correlation with the source code. If the compiler were to modify it (including changing its length) this correlation would be broken. > > >> this would require runtime type handling (and in fact several >> interpreted languages do something very similar today), which may work >> well with your interpreted language, but not in C. > > Non-interpreted languages are also capable of printing without needing > to tell the compiler what it already knows. At least the ones that > haven't inherited C's printf. > > Apart from C, I've only known Fortran have that requirement, and that > dates from the 1950s. I'd been coding for over 15 years before I came > across C's funny way of printing. The main difference is that in Fortran PRINT is a /statement/, while in C printf is a /function/. Being a statement, the Fortran compiler is allowed to interpret the PRINT code anyhow it wishes, and generate the appropriate instructions. C does not have formatting capabilities built in the language, it needs to delegate to runtime code, with this result (i.e. type information is lost when arguments are passed to a variadic function, so some gymnastics by the programmer is needed).
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-11-03 22:39 +0000 |
| Message-ID | <87lfswlh3k.fsf@bsb.me.uk> |
| In reply to | #147551 |
Bart <bc@freeuk.com> writes: > Non-interpreted languages are also capable of printing without needing > to tell the compiler what it already knows. At least the ones that > haven't inherited C's printf. As well as some that have. Haskell has a standard printf module which type-checks the format when specifiers like d, c, s and so on are used but which also supports a generic v specifier. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-11-03 23:06 +0100 |
| Message-ID | <qpnj12$17q$1@dont-email.me> |
| In reply to | #147546 |
On 03/11/2019 18:20, Bart wrote:
> On 03/11/2019 16:46, David Brown wrote:
>> On 03/11/2019 14:27, Bart wrote:
>
>>> The important thing is to have a format where you don't need to know
>>> the exact type of the thing being printed, just whether it's int,
>>> float, string or pointer. Or, very often, not even that - just print
>>> X, whatever type it happens to be, or print X with a given width.))
>>>
>>
>> I usually know the type of my variables and expressions, so don't see
>> that as an important thing at all. I /do/, however, agree that the
>> PRI macros are ugly, even though I understand why they exist.
>
> (1) A numeric type T exported from a library's header. You want to print
> it, but now you have to delve into the header to find out what type
> it is, to work out what format it needs.
>
I don't use types when I don't know their relevant characteristics. For
an integer type, its size and range is the important part. If I don't
know the type's range, how do I know what I can do with it and what
values it can store? The format specifier for printf for the type is a
very minor issue compared to not being able to use it at all.
> (Using an IDE to find that is not a solution: see (2).)
Using an IDE might be a convenient part of the solution, since (2) is
not an issue either.
>
> (2) Even when you know exactly the type T of an expression, you will be
> embedding the format string in dozens or hundred of sites within the
> code. Then T changes (eg. the library which exports T is updated.)
Have you ever heard the phrase "Don't repeat yourself", with the acronym
DRY? You write code to output the type once, and use it wherever it is
needed. If T changes, you change the one function.
Of course, that kind of coding might be unfamiliar to someone who
rejects majors, inline functions, typedefs, and other features aimed at
such abstractions in coding.
>
> (3) You define a type like this:
>
> #if cond
> int x;
> #elif
> double x;
> #endif
>
>
> Now you want print x; what format to use?
#if cond
int x;
#define PRIx %d
#elif
double x;
#define PRIx %f
#endif
Or, more likely, the conditional separates different typedefs and output
routines.
>
> (4) You have X of type T, and Y of type U, both compatible numeric
> types. Now you want to print the value of this expression:
>
> X*Y
>
> What format to use? What about when it changes to X*2+Y*3?. How
> about when the expression is complex that you don't know whether the
> type is int or double or unsigned long long int?
>
As I say, I don't write code using types that I don't know. So your
complaint is meaningless.
>
> The "%?" suggestion works with all of these when the type is numeric,
> and in many cases also when the type is a pointer or string.
It is an idea that can work in a more interpreted style of language. It
is not a bad idea, and could be very convenient. But it is neither
necessary, nor well suited to C.
If I wanted a more general "print this, no matter what it is" solution -
which, as I say, could be very convenient even though not necessary -
this is not the way I would want it in a language. I'd prefer something
based on function overloading. It's what you get in Python, where
"print x" is interpreted as "print str(x)", which in turn is "print
x.__str__()". It's what you get in C++ with "cout << x" (yes, there are
plenty of flaws with C++ iostreams - don't bother pointing them out).
If "%?" is something that works for you in your languages, great. That
does not mean it is something that other people would like in C.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-11-03 23:28 +0000 |
| Message-ID | <BoJvF.123253$m0L.2016@fx15.am4> |
| In reply to | #147556 |
On 03/11/2019 22:06, David Brown wrote:
> On 03/11/2019 18:20, Bart wrote:
>> (1) A numeric type T exported from a library's header. You want to print
>> it, but now you have to delve into the header to find out what type
>> it is, to work out what format it needs.
>>
>
> I don't use types when I don't know their relevant characteristics.
You do some includes such as:
#include <windows.h>
#include <gtk.h>
and you're importing possibly 1000s of types. You're not going to be
able to keep track of them. And every so often, you will need to
printout values of those types, or the results of calculations with
those types.
> Have you ever heard the phrase "Don't repeat yourself", with the acronym
> DRY? You write code to output the type once, and use it wherever it is
> needed. If T changes, you change the one function.
Huh? You write this
int nsymbols;
In 100 places in the program, you might have code like this:
printf("Symbol %d out of %d",i, nsymbols);
Then one day, you decide to change it to:
long long int nsymbols;
Now all those %d's that refer to nsymbols in a format string need to be
changed. Plus possibly variables such as that 'i' above, and /its/ format.
If nsymbols is defined in some imported header, you might not even be
aware of any change.
> Of course, that kind of coding might be unfamiliar to someone who
> rejects majors, inline functions, typedefs, and other features aimed at
> such abstractions in coding.
Yet the entire C language rejects type abstraction when it comes to
printf formats!
> #if cond
> int x;
> #define PRIx %d
> #elif
> double x;
> #define PRIx %f
> #endif
Yuck.
However nobody actually does it. (Look at one of those 50-line #if/#elif
chains of conditionals that end up defining some vital type. They NEVER
also define a corresponding print format.)
And this definition could be inside someone else's header that you are
importing.
All you want to do is quickly print the value of .st_rdev of a 'stat'
struct, of which one of half a dozen variations could be conditionally
defined. Good luck finding a print format defined too! It's just not
going to happen.
Your best bet might be actually printing as float, and converting to
float, provided the magnitude is under 2**52, but it's a hell of thing
to have to do, especially if you'd prefer it as hex!
printf("s.st_rdev = %f\n", (double)s.st_rdev);
compared with:
printf("%=?\n", s.strdev);
> As I say, I don't write code using types that I don't know. So your
> complaint is meaningless.
No it isn't. It's perfectly legitimate. You're debugging someone's
100,000-line project with a thousand types, and thousands of variables
and functions of different types, and you need to print out the value of
the index here:
a[f(x)+y]=0;
as printf("f(x)+y = %...\n", f(x)+y); but what goes in the "..."? You
have to assume it is something compatible with int or size_t (you don't
even know what type array indices are supposed to be!), but you can't
tell just from that fragment.
All your suggestions are workarounds and mitigations for a fundamental
short-coming.
>>
>> The "%?" suggestion works with all of these when the type is numeric,
>> and in many cases also when the type is a pointer or string.
>
> It is an idea that can work in a more interpreted style of language. It
> is not a bad idea, and could be very convenient.
It is. I can write for my above example:
printf("f(x)+y= %?\n",f(x)+y);
and not know nor care what the relevant types are. I've just tried it
and it works with int, long long int, double or even char*. It's less
work, more productive and less error prone.
> If "%?" is something that works for you in your languages, great. That
> does not mean it is something that other people would like in C.
I think they would. Ben said in another post that Haskell has C-like
formats, but also "v" that works for any variable. That is the
equivalent of my "?" (which I can change to "v" if that has no existing
meaning).
But I can't imagine when someone writing Haskell would want to bother
with anything other than "v".
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-11-04 11:00 +0100 |
| Message-ID | <qposrb$2sq$1@dont-email.me> |
| In reply to | #147561 |
On 04/11/2019 00:28, Bart wrote:
> On 03/11/2019 22:06, David Brown wrote:
>> On 03/11/2019 18:20, Bart wrote:
>
>>> (1) A numeric type T exported from a library's header. You want to print
>>> it, but now you have to delve into the header to find out what type
>>> it is, to work out what format it needs.
>>>
>>
>> I don't use types when I don't know their relevant characteristics.
>
> You do some includes such as:
>
> #include <windows.h>
> #include <gtk.h>
I don't. C is a terrible choice of language for gui programming (on
Windows or Linux). The main reason MS never bothered to support C99 in
their C compiler and libraries (until very recently) is that few sane
developers have used C for gui application programming since long before
C99 was established.
But we will leave that aside for now, and assume my C code has include
files with thousands of types.
>
> and you're importing possibly 1000s of types. You're not going to be
> able to keep track of them. And every so often, you will need to
> printout values of those types, or the results of calculations with
> those types.
What I said, is that I don't use types when I don't know their
/relevant/ characteristics.
Re-read that. Maybe re-read it again.
For the majority of types, the relevant characteristics for me, as a
user of the include files, is nothing more than that they are
identifiers I can't use in my own code. A file that includes headers
like "windows.h" is likely to use perhaps 0.1 % of the functions, types,
constants, macros, etc., declared in those headers.
For most of the types that would be used, the relevant characteristics
might be no more than "I get values of this type like this, I send them
out like that". Gui-related types might include handles, widgits,
colours, etc. You don't care about the details. You often don't care
if it is a handle, or a struct, or a pointer to a struct. You don't
care if the underlying type is big or small - you only care that you can
use it in the way documented by the library.
Then you might be left with a few - a very few - numeric types. Things
like "DWORD" or "int32" - hangovers from the past, when using libraries
that were developed before C99 was standardised. You know what size
these types are, they don't change, and if you don't know, you don't use
them.
>
>> Have you ever heard the phrase "Don't repeat yourself", with the
>> acronym DRY? You write code to output the type once, and use it
>> wherever it is needed. If T changes, you change the one function.
>
> Huh? You write this
>
> int nsymbols;
>
> In 100 places in the program, you might have code like this:
>
> printf("Symbol %d out of %d",i, nsymbols);
>
> Then one day, you decide to change it to:
>
> long long int nsymbols;
>
> Now all those %d's that refer to nsymbols in a format string need to be
> changed. Plus possibly variables such as that 'i' above, and /its/ format.
No, you don't write that.
You plan your program. Is it realistic to think that the type of
"nsymbols" would change - that 2 G symbols will not be enough? If that
is the case, you write:
typedef int symbolcount_t;
symbolcount_t nsymbols;
#define PRIsymbolcount d
void debug_print_symbolcounts(symbolcount__t i) {
printf("Symbol %" PRIsymbolcount " out of %" PRIsymbolcount,
i, nsymbols);
}
Or maybe, if you don't like printf format macros (and lets be honest, no
one does - even if it is the least bad solution, it is still ugly), you
write:
typedef int symbolcount_t;
symbolcount_t nsymbols;
void print_symbolcounts(symbolcount_t i) {
_Static_assert(sizeof(symbolcount_t) == sizeof(int),
"Fix this function if symbolcount_t changes");
printf("%d", i);
}
You abstract things that are likely to change. That lets you make
changes to the program later. It means that you can change your type,
or perhaps the format of the output. (What help is "%?" if you later
decide the numbers should have thousands separators in them?)
Of course you can't abstract everything, and you can't predict all
changes of future versions. So sometimes you will be faced with doing a
search and replace on the /ten/ occurrences of the print string in the code.
And sometimes you are faced with firing the programmer who wrote the
same print string /hundreds/ of times in the code.
>
> If nsymbols is defined in some imported header, you might not even be
> aware of any change.
I am aware of such changes.
Perhaps there are weaknesses in your development practices that let such
problems slip through unnoticed. I am sure others could find plenty of
flaws or "improvement areas" in my own development practices, but this
is not one of them.
There are three key methods here.
1) I don't use different versions of headers without checking what
changes might be relevant. API's of libraries, OS's, etc., do not
change in this way, so the issue is only realistic for major updates in
a library, or for code under development. And you don't use different
versions of code being developed without understanding the changes.
2) If there is something that is likely to change, or if I am making
assumptions that could be wrong in the future or in different
circumstances, I use static assertions or appropriate conditional
compilation. When something changes, the code is either automatically
adapted, or there is a compile-time error.
3) I use static error checking to catch problems, with heavy use of
warnings appropriate to the code - and I pay attention to any warnings.
(This is not C specific - I do it with any programming, adjusted for the
features and tools of the language.)
>
>> Of course, that kind of coding might be unfamiliar to someone who
>> rejects majors, inline functions, typedefs, and other features aimed
>> at such abstractions in coding.
>
> Yet the entire C language rejects type abstraction when it comes to
> printf formats!
>
>> #if cond
>> int x;
>> #define PRIx %d
>> #elif
>> double x;
>> #define PRIx %f
>> #endif
>
> Yuck.
>
> However nobody actually does it. (Look at one of those 50-line #if/#elif
> chains of conditionals that end up defining some vital type. They NEVER
> also define a corresponding print format.)
>
It is a way to handle the situation. It's a bit ugly - no disagreement
there. But you have the ugliness hidden away.
There are other methods, of course. I mentioned one earlier in this
post. Another idea is to use _Generic macros (which are ugly to define,
but easy to use).
printf is flexible, but it has its limitations. There are lots of
things it can't do. If it doesn't suit your needs, solve the problem in
a different way - printf calls are not the only way to do output in C.
Programming is about finding solutions to problems, not about assuming
there is only one solution and then trying to invent problems it can't
solve.
> And this definition could be inside someone else's header that you are
> importing.
>
> All you want to do is quickly print the value of .st_rdev of a 'stat'
> struct, of which one of half a dozen variations could be conditionally
> defined. Good luck finding a print format defined too! It's just not
> going to happen.
>
> Your best bet might be actually printing as float, and converting to
> float, provided the magnitude is under 2**52, but it's a hell of thing
> to have to do, especially if you'd prefer it as hex!
>
> printf("s.st_rdev = %f\n", (double)s.st_rdev);
>
> compared with:
>
> printf("%=?\n", s.strdev);
>
>
>> As I say, I don't write code using types that I don't know. So your
>> complaint is meaningless.
>
> No it isn't. It's perfectly legitimate. You're debugging someone's
> 100,000-line project with a thousand types, and thousands of variables
> and functions of different types, and you need to print out the value of
> the index here:
>
> a[f(x)+y]=0;
>
> as printf("f(x)+y = %...\n", f(x)+y); but what goes in the "..."?
printf("f(x)+y = %zu\n", (size_t) (f(x)+y));
I know enough about the types to know this is valid.
Oh, and I know how to use a debugger. It's often a handy tool when
debugging.
> You
> have to assume it is something compatible with int or size_t (you don't
> even know what type array indices are supposed to be!), but you can't
> tell just from that fragment.
>
> All your suggestions are workarounds and mitigations for a fundamental
> short-coming.
No one has ever claimed that "printf" does everything. What you call
"workarounds and mitigations", other people call "finding solutions" or
"programming".
I think you are so used to living in your own little world with your own
little programming languages, that you have lost your understanding of
how /real/ programming is done. When you have a situation that you
can't handle simply and immediately in your own language, your answer is
to change the language. For other people, the answer is to /use/ the
language they have.
>
>>>
>>> The "%?" suggestion works with all of these when the type is numeric,
>>> and in many cases also when the type is a pointer or string.
>>
>> It is an idea that can work in a more interpreted style of language.
>> It is not a bad idea, and could be very convenient.
>
> It is. I can write for my above example:
>
> printf("f(x)+y= %?\n",f(x)+y);
>
> and not know nor care what the relevant types are. I've just tried it
> and it works with int, long long int, double or even char*. It's less
> work, more productive and less error prone.
Tell me how you print the value in binary. Tell me how you choose to
add thousands separators. Tell me how this works if f(x) returns a
string and y is a character, or where the types are matrices.
C printf can't solve these. Neither can your language, I believe.
Other languages - such as Python and C++ - can handle them neatly (once
you have written the appropriate support code for your types).
Different languages are useful for different purposes.
Your "%?" is a step up in convenience for printf. But it is only a
small step up, and in C the cost would be far too high. If you like it
for your own language, that's up to you - but it is not something that C
is missing in any way.
>
>> If "%?" is something that works for you in your languages, great.
>> That does not mean it is something that other people would like in C.
>
> I think they would. Ben said in another post that Haskell has C-like
> formats, but also "v" that works for any variable. That is the
> equivalent of my "?" (which I can change to "v" if that has no existing
> meaning).
Haskell is not C. There are vast amounts of cool features in Haskell
that C does not have - and equally, vast amounts of things that are
simple to do in C, but much harder to handle in a language like Haskell.
>
> But I can't imagine when someone writing Haskell would want to bother
> with anything other than "v".
You base this on your vast experience with Haskell programming?
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-11-04 11:14 +0000 |
| Message-ID | <5KTvF.90430$Cx1.88757@fx10.am4> |
| In reply to | #147568 |
On 04/11/2019 10:00, David Brown wrote:
> On 04/11/2019 00:28, Bart wrote:
>> On 03/11/2019 22:06, David Brown wrote:
>>> On 03/11/2019 18:20, Bart wrote:
>>
>>>> (1) A numeric type T exported from a library's header. You want to print
>>>> it, but now you have to delve into the header to find out what type
>>>> it is, to work out what format it needs.
>>>>
>>>
>>> I don't use types when I don't know their relevant characteristics.
>>
>> You do some includes such as:
>>
>> #include <windows.h>
>> #include <gtk.h>
>
> I don't.
So your solution to the problem of printing somewhat opaque numeric
types is to either never import external libraries, or never print them,
or do neither.
Yeah, that works.
Another way is never to write any C (I can tell you that works pretty well!)
However let's take the example of a much smaller library, SDL. Its
headers define around 60 named structs, that you might need to create
instances of in your code, and assign to their elements, and maybe
sometimes even print out their values.
What strategy to use for that, other than having to go and look up every
single one to find out if its %s or %d or %u or %lld?
Well, you might just assume there are no 64-bit elements, and few if any
floats (I don't know), then use %d and cross your fingers. If you get
negative values that don't look right, try %u.
Yeah, that sounds a great way to program!
> typedef int symbolcount_t;
> symbolcount_t nsymbols;
> #define PRIsymbolcount d
>
> void debug_print_symbolcounts(symbolcount__t i) {
> printf("Symbol %" PRIsymbolcount " out of %" PRIsymbolcount,
> i, nsymbols);
> }
You're making my case for me I think. People may want/need to use C for
various reason, but they don't want to be forced to code like the above.
> Of course you can't abstract everything, and you can't predict all
> changes of future versions. So sometimes you will be faced with doing a
> search and replace on the /ten/ occurrences of the print string in the code.
Occurrences where the variable being printed is part of an expression
and its change of type may or may not effect the type of the expression.
> printf("f(x)+y = %zu\n", (size_t) (f(x)+y));
>
> I know enough about the types to know this is valid.
Or erroneous. The result might be a negative, signed integer, or a float.
> Tell me how you print the value in binary. Tell me how you choose to
> add thousands separators.
Those are C printf limitations. The "%?" transformation is done at
compile-time; conversion to binary must be done at runtime. Supporting
it would mean an entirely new feature.
> Tell me how this works if f(x) returns a
> string and y is a character,
Huh? If the types are incompatible, it won't compile. But
string+character (ie. char* + int) is legal in C.
> or where the types are matrices.
Is that what is called a 'strawman' argument? No point in replacing a
coach and horses with a car, because a car can't fly...
> C printf can't solve these. Neither can your language, I believe.
See for yourself:
!--------------------------------------------------------------
proc start=
var int a := 12345
var real x := 0.785398
println a ! decimal
println =a ! with label
println a:"h" ! hex
println a:"b" ! binary
println a:"x3" ! base-3
println a:"s," ! decimal, 1000s separator ","
println a:"hs_" ! hex, 10000s separator "_"
println x ! float
println (a+x).typestr ! type of a+x
fprintln "a=<#>, x=#", a:"12", x:"e"
! fmt str, field widths, float style
end
!--------------------------------------------------------------
Further, try it for yourself (you will need 64-bit Linux):
(1) Download this C file:
https://github.com/sal55/qx/blob/master/mu64.c
(2) Build it:
gcc mu64.c -omu -lm -ldl
(3) Create a file test.m containing the above function
(4) Compile it via a C target:
./mu test
(5) Run it:
./test
(The language also supports 128-bit printing, but that currently relies
on some inline ASM which can't be translated to C.)
> Other languages - such as Python and C++ - can handle them neatly (once
> you have written the appropriate support code for your types).
> Different languages are useful for different purposes.
We are talking about absolute basics. Even BASIC can do this (and could
do it in 1964):
LET A = 12345
PRINT A
>> But I can't imagine when someone writing Haskell would want to bother
>> with anything other than "v".
>
> You base this on your vast experience with Haskell programming?
No, on my vast experience of hardly ever needing nor wanting to tell
Print the type of the thing I'm printing.
(The exceptions are when you want to override the default
representation, eg. show 'char*' as a pointer rather than a string.)
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-11-04 11:22 +0000 |
| Message-ID | <87eeynlwc7.fsf@bsb.me.uk> |
| In reply to | #147568 |
David Brown <david.brown@hesbynett.no> writes:
<cut>
> You plan your program. Is it realistic to think that the type of
> "nsymbols" would change - that 2 G symbols will not be enough? If that
> is the case, you write:
>
> typedef int symbolcount_t;
> symbolcount_t nsymbols;
> #define PRIsymbolcount d
#define PRIsymbolcount "d"
> void debug_print_symbolcounts(symbolcount__t i) {
> printf("Symbol %" PRIsymbolcount " out of %" PRIsymbolcount,
> i, nsymbols);
> }
>
> Or maybe, if you don't like printf format macros (and lets be honest, no
> one does - even if it is the least bad solution, it is still ugly), you
> write:
>
> typedef int symbolcount_t;
> symbolcount_t nsymbols;
>
> void print_symbolcounts(symbolcount_t i) {
> _Static_assert(sizeof(symbolcount_t) == sizeof(int),
> "Fix this function if symbolcount_t changes");
> printf("%d", i);
> }
I think I might use _Generic here because checking the size is not
always going to be enough:
_Static_assert(
_Generic(i, int: 1, default: 0),
"Check this because symbolcount_t is not compatible with int."
);
This works (in both clang and gcc) with -std=c11 -pedantic, but I am not
sure that _Generic /must/ be allowed here. It would be a shame if
generic selections were not considered to be standard constant
expressions. Have I missed something in the standard?
<cut>
Bart writes:
>> I think they would. Ben said in another post that Haskell has C-like
>> formats, but also "v" that works for any variable. That is the
>> equivalent of my "?" (which I can change to "v" if that has no existing
>> meaning).
>
> Haskell is not C. There are vast amounts of cool features in Haskell
> that C does not have - and equally, vast amounts of things that are
> simple to do in C, but much harder to handle in a language like
> Haskell.
Of course. Mind you, a better example would have been Go (since it's
designed in part by DMR), though Go does not check the format at compile
time but at run time. It also uses %v.
>> But I can't imagine when someone writing Haskell would want to bother
>> with anything other than "v".
There are many reasons to use other formats, but an obvious one is to
restrict printing to the type given in the format. This will act a bit like
the _Static_assert above.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-11-04 13:10 +0100 |
| Message-ID | <qpp4ga$eq6$1@dont-email.me> |
| In reply to | #147570 |
On 04/11/2019 12:22, Ben Bacarisse wrote:
> David Brown <david.brown@hesbynett.no> writes:
> <cut>
>> You plan your program. Is it realistic to think that the type of
>> "nsymbols" would change - that 2 G symbols will not be enough? If that
>> is the case, you write:
>>
>> typedef int symbolcount_t;
>> symbolcount_t nsymbols;
>> #define PRIsymbolcount d
>
> #define PRIsymbolcount "d"
Indeed.
>
>> void debug_print_symbolcounts(symbolcount__t i) {
>> printf("Symbol %" PRIsymbolcount " out of %" PRIsymbolcount,
>> i, nsymbols);
>> }
>>
>> Or maybe, if you don't like printf format macros (and lets be honest, no
>> one does - even if it is the least bad solution, it is still ugly), you
>> write:
>>
>> typedef int symbolcount_t;
>> symbolcount_t nsymbols;
>>
>> void print_symbolcounts(symbolcount_t i) {
>> _Static_assert(sizeof(symbolcount_t) == sizeof(int),
>> "Fix this function if symbolcount_t changes");
>> printf("%d", i);
>> }
>
> I think I might use _Generic here because checking the size is not
> always going to be enough:
>
> _Static_assert(
> _Generic(i, int: 1, default: 0),
> "Check this because symbolcount_t is not compatible with int."
> );
I mentioned _Generic later on as a way to aid printing, but I hadn't
thought of using them in a static assert like this. Thank you for the idea!
>
> This works (in both clang and gcc) with -std=c11 -pedantic, but I am not
> sure that _Generic /must/ be allowed here. It would be a shame if
> generic selections were not considered to be standard constant
> expressions. Have I missed something in the standard?
>
> <cut>
> Bart writes:
>>> I think they would. Ben said in another post that Haskell has C-like
>>> formats, but also "v" that works for any variable. That is the
>>> equivalent of my "?" (which I can change to "v" if that has no existing
>>> meaning).
>>
>> Haskell is not C. There are vast amounts of cool features in Haskell
>> that C does not have - and equally, vast amounts of things that are
>> simple to do in C, but much harder to handle in a language like
>> Haskell.
>
> Of course. Mind you, a better example would have been Go (since it's
> designed in part by DMR), though Go does not check the format at compile
> time but at run time. It also uses %v.
>
>>> But I can't imagine when someone writing Haskell would want to bother
>>> with anything other than "v".
>
> There are many reasons to use other formats, but an obvious one is to
> restrict printing to the type given in the format. This will act a bit like
> the _Static_assert above.
>
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-11-04 10:03 -0800 |
| Message-ID | <lneeyn5xjj.fsf@kst-u.example.com> |
| In reply to | #147570 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
[...]
> I think I might use _Generic here because checking the size is not
> always going to be enough:
>
> _Static_assert(
> _Generic(i, int: 1, default: 0),
> "Check this because symbolcount_t is not compatible with int."
> );
>
> This works (in both clang and gcc) with -std=c11 -pedantic, but I am not
> sure that _Generic /must/ be allowed here. It would be a shame if
> generic selections were not considered to be standard constant
> expressions. Have I missed something in the standard?
I think it's covered in 6.6, which has this contraint in p2:
Constant expressions shall not contain assignment, increment,
decrement, function-call, or comma operators, except when they
are contained within a subexpression that is not evaluated.
Which implies, I think, that a generic selection is a constant
expression if the result expression is a constant expression,
even if the other subexpressions are not.
gcc and clang seem to agree.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-11-04 19:36 +0000 |
| Message-ID | <87r22njuxc.fsf@bsb.me.uk> |
| In reply to | #147585 |
Keith Thompson <kst-u@mib.org> writes: > Ben Bacarisse <ben.usenet@bsb.me.uk> writes: > [...] >> I think I might use _Generic here because checking the size is not >> always going to be enough: >> >> _Static_assert( >> _Generic(i, int: 1, default: 0), >> "Check this because symbolcount_t is not compatible with int." >> ); >> >> This works (in both clang and gcc) with -std=c11 -pedantic, but I am not >> sure that _Generic /must/ be allowed here. It would be a shame if >> generic selections were not considered to be standard constant >> expressions. Have I missed something in the standard? > > I think it's covered in 6.6, which has this contraint in p2: > > Constant expressions shall not contain assignment, increment, > decrement, function-call, or comma operators, except when they > are contained within a subexpression that is not evaluated. > > Which implies, I think, that a generic selection is a constant > expression if the result expression is a constant expression, > even if the other subexpressions are not. I'm sure that's right, but I skipped over that because it's saying what must /not/ be in a constant expression. Presumably it's a case of everything else is OK. > gcc and clang seem to agree. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-11-05 10:04 -0800 |
| Message-ID | <ln7e4e5hdm.fsf@kst-u.example.com> |
| In reply to | #147586 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> Keith Thompson <kst-u@mib.org> writes:
>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>> [...]
>>> I think I might use _Generic here because checking the size is not
>>> always going to be enough:
>>>
>>> _Static_assert(
>>> _Generic(i, int: 1, default: 0),
>>> "Check this because symbolcount_t is not compatible with int."
>>> );
>>>
>>> This works (in both clang and gcc) with -std=c11 -pedantic, but I am not
>>> sure that _Generic /must/ be allowed here. It would be a shame if
>>> generic selections were not considered to be standard constant
>>> expressions. Have I missed something in the standard?
>>
>> I think it's covered in 6.6, which has this contraint in p2:
>>
>> Constant expressions shall not contain assignment, increment,
>> decrement, function-call, or comma operators, except when they
>> are contained within a subexpression that is not evaluated.
>>
>> Which implies, I think, that a generic selection is a constant
>> expression if the result expression is a constant expression,
>> even if the other subexpressions are not.
>
> I'm sure that's right, but I skipped over that because it's saying what
> must /not/ be in a constant expression. Presumably it's a case of
> everything else is OK.
I believe so, yes -- and admittedly what I wrote above was not as
rigorous as it should have been.
6.6 defines a *constant-expression* syntactically:
constant-expression:
conditional-expression
Some constructs require a constant expression, for example
enumerator:
enumeration-constant
enumeration-constant = constant-expression
Which means that the expression on the right of the = in an enumerator
(a) has to be a conditional-expression and (b) has to satisify the
constraints of a constant-expression. (And it also has to satisfy the
constraint in 6.7.2.2, that it's an integer constant expression at has a
value representable as an int.)
A generic selection in a static assert doesn't violate any of the
constraints of a constant-expression -- but it's required to be an
integer constant expression, and it doesn't meet those requirements
(6.6p6). (Constant expressions have a blacklist of things that
aren't allowed. Integer constant expressions have a whitelist of
things that are allowed.
But the requirement for an integer constant expression in a
_Static_assert is a "shall" outside a constraint, so violating it has
undefined behavior.
>> gcc and clang seem to agree.
gcc and clang seem to be permitting _Generic in integer constant
expressions (or at least not rejecting it). I believe they are
not required to do so.
I find it odd that having a _Static_assert with something that is a
constant expression but is not an integer constant expression was
left as undefined behavior. If compilers don't behave reasonably
(doing more than what the standard requires), that could be a source
of bugs that are difficult to detect.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2019-11-04 20:58 -0800 |
| Message-ID | <868sougbqs.fsf@linuxsc.com> |
| In reply to | #147585 |
Keith Thompson <kst-u@mib.org> writes: > Ben Bacarisse <ben.usenet@bsb.me.uk> writes: > [...] > >> I think I might use _Generic here because checking the size is not >> always going to be enough: >> >> _Static_assert( >> _Generic(i, int: 1, default: 0), >> "Check this because symbolcount_t is not compatible with int." >> ); >> >> This works (in both clang and gcc) with -std=c11 -pedantic, but I am not >> sure that _Generic /must/ be allowed here. It would be a shame if >> generic selections were not considered to be standard constant >> expressions. Have I missed something in the standard? > > I think it's covered in 6.6, which has this contraint in p2: > > Constant expressions shall not contain assignment, increment, > decrement, function-call, or comma operators, except when they > are contained within a subexpression that is not evaluated. > > Which implies, I think, that a generic selection is a constant > expression if the result expression is a constant expression, > even if the other subexpressions are not. What a strange inference. The quoted sentence can tell us only when an expression is not a constant expression, never when it is a constant expression. Besides which, a _Static_assert needs not just a constant expression but an integer constant expression.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2019-11-04 22:01 -0800 |
| Message-ID | <864kzig8v6.fsf@linuxsc.com> |
| In reply to | #147570 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> David Brown <david.brown@hesbynett.no> writes:
> <cut>
>
>> You plan your program. Is it realistic to think that the type of
>> "nsymbols" would change - that 2 G symbols will not be enough? If that
>> is the case, you write:
>>
>> typedef int symbolcount_t;
>> symbolcount_t nsymbols;
>> #define PRIsymbolcount d
>
> #define PRIsymbolcount "d"
>
>> void debug_print_symbolcounts(symbolcount__t i) {
>> printf("Symbol %" PRIsymbolcount " out of %" PRIsymbolcount,
>> i, nsymbols);
>> }
>>
>> Or maybe, if you don't like printf format macros (and lets be honest, no
>> one does - even if it is the least bad solution, it is still ugly), you
>> write:
>>
>> typedef int symbolcount_t;
>> symbolcount_t nsymbols;
>>
>> void print_symbolcounts(symbolcount_t i) {
>> _Static_assert(sizeof(symbolcount_t) == sizeof(int),
>> "Fix this function if symbolcount_t changes");
>> printf("%d", i);
>> }
>
> I think I might use _Generic here because checking the size is not
> always going to be enough:
>
> _Static_assert(
> _Generic(i, int: 1, default: 0),
> "Check this because symbolcount_t is not compatible with int."
> );
>
> This works (in both clang and gcc) with -std=c11 -pedantic, but I am not
> sure that _Generic /must/ be allowed here. It would be a shame if
> generic selections were not considered to be standard constant
> expressions. Have I missed something in the standard?
An implementation may accept it. However, an argument can be made
that an implementation may rightfully reject this _Static_assert
(and most _Static_assert declarations with a _Generic controlling
expression) because it has undefined behavior. Undefined behavior
arises because the controlling expression of a _Static_assert "shall
[not in a Constraint] be an integer constant expression". Integer
constant expressions are limited in what their operands can be:
[They] "shall have integer type and shall only have operands that
are integer constants, enumeration constants, character constants,
sizeof expressions whose results are integer constants, _Alignof
expressions, and floating constants that are the immediate operands
of casts." The operand 'i' is not any of those. We might say the
operand is not 'i' but the type of the expression 'i', but types too
are not any of the things on the list. We might say the operand 'i'
is not evaluated so it doesn't count, but not being evaluated looks
like it doesn't matter for the ICE operand requirement. For
example,
_Static_assert( 0 ? i : 1, "OOPS" );
gives (with gcc) a diagnostic saying "expression in static assertion
is not an integer constant expression".
Don't get me wrong, I don't think this reading is what the authors
intended. But I think the construction is reasonable based just on
what text appears in the Standard.
One other item. The condition used in the _Static_assert above is
more restrictive than it needs to be. The printf() call will work
if the type is 'int', but it will also work with 'signed char', or
'short', etc, because of integer promotions. The assertion can be
fixed by changing the controlling expression of the _Generic()
expression, thusly:
_Generic( 0 ? 0 : i, int: 1, default: 0 )
which will convert any sub-int integer type to int, and leave others
alone.
[toc] | [prev] | [next] | [standalone]
Page 2 of 5 — ← Prev page 1 [2] 3 4 5 Next page →
Back to top | Article view | comp.lang.c
csiph-web