Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #147447 > unrolled thread

memcpy not memcpying?

Started byDFS <nospam@dfs.com>
First post2019-11-01 08:42 -0400
Last post2019-11-01 23:19 +0000
Articles 20 on this page of 88 — 19 participants

Back to article view | Back to comp.lang.c


Contents

  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 →


#147520

FromBart <bc@freeuk.com>
Date2019-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]


#147521

FromKeith Thompson <kst-u@mib.org>
Date2019-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]


#147536

FromBart <bc@freeuk.com>
Date2019-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]


#147543

FromDavid Brown <david.brown@hesbynett.no>
Date2019-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]


#147546

FromBart <bc@freeuk.com>
Date2019-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]


#147548

FromManfred <noname@add.invalid>
Date2019-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]


#147551

FromBart <bc@freeuk.com>
Date2019-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]


#147555

FromManfred <noname@add.invalid>
Date2019-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]


#147557

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-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]


#147556

FromDavid Brown <david.brown@hesbynett.no>
Date2019-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]


#147561

FromBart <bc@freeuk.com>
Date2019-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]


#147568

FromDavid Brown <david.brown@hesbynett.no>
Date2019-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]


#147569

FromBart <bc@freeuk.com>
Date2019-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]


#147570

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-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]


#147572

FromDavid Brown <david.brown@hesbynett.no>
Date2019-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]


#147585

FromKeith Thompson <kst-u@mib.org>
Date2019-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]


#147586

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-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]


#147630

FromKeith Thompson <kst-u@mib.org>
Date2019-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]


#147591

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2019-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]


#147592

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2019-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