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


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

When parameters to printf are in memory

Started byJames Harris <james.harris.1@gmail.com>
First post2016-09-29 16:20 +0100
Last post2016-10-02 21:27 +0200
Articles 20 on this page of 44 — 9 participants

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


Contents

  When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-09-29 16:20 +0100
    Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-09-29 16:43 +0100
      Re: When parameters to printf are in memory Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-29 20:30 +0100
      Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-09-29 21:23 +0100
      Re: When parameters to printf are in memory BartC <bc@freeuk.com> - 2016-09-29 22:03 +0100
        Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-09-29 22:35 +0100
          Re: When parameters to printf are in memory BartC <bc@freeuk.com> - 2016-09-29 23:11 +0100
            Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-09-30 19:53 +0100
              Re: When parameters to printf are in memory Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-30 20:53 +0100
                Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-10-01 09:08 +0100
                  Re: When parameters to printf are in memory BartC <bc@freeuk.com> - 2016-10-01 11:15 +0100
                    Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-10-04 08:32 +0100
                  Re: When parameters to printf are in memory Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-01 11:15 +0100
                    Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-10-04 08:28 +0100
                      Re: When parameters to printf are in memory Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-04 09:49 +0100
                        Re: When parameters to printf are in memory BartC <bc@freeuk.com> - 2016-10-04 11:43 +0100
                          Re: When parameters to printf are in memory Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-04 13:42 +0100
                            Re: When parameters to printf are in memory BartC <bc@freeuk.com> - 2016-10-04 14:03 +0100
                              Re: When parameters to printf are in memory Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-04 14:16 +0100
                        Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-10-04 20:01 +0100
                          Re: When parameters to printf are in memory Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-04 20:24 +0100
                            Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-10-04 20:40 +0100
                              Re: When parameters to printf are in memory Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-04 22:51 +0100
              Re: When parameters to printf are in memory "James R. Kuyper" <jameskuyper@verizon.net> - 2016-10-04 14:25 -0400
                Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-10-04 20:31 +0100
    Re: When parameters to printf are in memory BartC <bc@freeuk.com> - 2016-09-29 17:03 +0100
      Re: When parameters to printf are in memory gazelle@shell.xmission.com (Kenny McCormack) - 2016-09-30 12:20 +0000
        Re: When parameters to printf are in memory Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-30 05:55 -0700
        Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-09-30 20:06 +0100
          Re: When parameters to printf are in memory gazelle@shell.xmission.com (Kenny McCormack) - 2016-09-30 22:01 +0000
            Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-10-01 09:15 +0100
          Re: When parameters to printf are in memory Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-30 23:18 -0700
            Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-10-01 09:32 +0100
    Re: When parameters to printf are in memory jacobnavia <jacob@jacob.remcomp.fr> - 2016-09-29 18:35 +0200
      Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-09-29 19:55 +0100
        Re: When parameters to printf are in memory jacobnavia <jacob@jacob.remcomp.fr> - 2016-09-29 21:22 +0200
    Re: When parameters to printf are in memory Barry Schwarz <schwarzb@dqel.com> - 2016-09-29 11:20 -0700
      Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-09-29 20:08 +0100
    Re: When parameters to printf are in memory Lőrinczy Zsigmond <nospam@for.me> - 2016-10-02 20:15 +0200
      Re: When parameters to printf are in memory Lőrinczy Zsigmond <nospam@for.me> - 2016-10-02 20:19 +0200
        Re: When parameters to printf are in memory gazelle@shell.xmission.com (Kenny McCormack) - 2016-10-02 18:29 +0000
          Re: When parameters to printf are in memory Lőrinczy Zsigmond <nospam@for.me> - 2016-10-03 07:04 +0200
            Re: When parameters to printf are in memory James Harris <james.harris.1@gmail.com> - 2016-10-04 08:36 +0100
      Re: When parameters to printf are in memory jacobnavia <jacob@jacob.remcomp.fr> - 2016-10-02 21:27 +0200

Page 1 of 3  [1] 2 3  Next page →


#94244 — When parameters to printf are in memory

FromJames Harris <james.harris.1@gmail.com>
Date2016-09-29 16:20 +0100
SubjectWhen parameters to printf are in memory
Message-ID<nsjbgn$o4k$1@dont-email.me>
Imagine an array holding an arbitrary number of values which need to be 
supplied to one of the printf family of functions. Normally, the values 
passed to such a function would be arguments but in this case they are 
in memory.

Can the elements be passed as arguments?

To make an example, imagine the following struct (untested):

   struct {
     char *text;
     union any parms[];
   };

Naturally, text is a pointer to the string and parms is the array. I am 
not sure that a union (definition not shown, for brevity) can be used 
the way that I have used it but you can probably guess that the idea is 
to specify that each element of the array can be any data type specified 
in the union.

Putting the union issue aside, the idea is that text and parms would be 
fed to a printf family function such as

   snprintf(dest, size, text, P);

The parms which are in memory and are of arbitrary length need to go in 
position P.

Can that be done in C (without writing the code needed to scan the 
string explicitly)?


-- 
James Harris

[toc] | [next] | [standalone]


#94247

FromJames Harris <james.harris.1@gmail.com>
Date2016-09-29 16:43 +0100
Message-ID<nsjcq7$sit$1@dont-email.me>
In reply to#94244
On 29/09/2016 16:35, Stefan Ram wrote:
> James Harris <james.harris.1@gmail.com> writes:
>> Imagine an array holding an arbitrary number of values which need to be
>> supplied to one of the printf family of functions. Normally, the values
>> passed to such a function would be arguments but in this case they are
>> in memory.
>
>   Are you looking for
>
> 7.21.6.12 The vsnprintf function
> int vsnprintf( char * restrict s, size_t n,
>   char const * restrict format, va_list arg );
>
>   or
>
> 7.21.6.13 The vsprintf function
> int vsprintf( char * restrict s,
>   char const * restrict format, va_list arg );

I don't think so because it looks as though a va_list cannot portably be 
represented as an array. I'd be happy to be told I am wrong....


-- 
James Harris

[toc] | [prev] | [next] | [standalone]


#94262

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-29 20:30 +0100
Message-ID<87r3821p1z.fsf@bsb.me.uk>
In reply to#94247
ram@zedat.fu-berlin.de (Stefan Ram) writes:

> James Harris <james.harris.1@gmail.com> writes:
>>I don't think so because it looks as though a va_list cannot
>>portably be represented as an array. I'd be happy to be told
>>I am wrong....
>
>   But what you seem to need is a means to convert
>   an array into a va_list.

That would do, but there's no portable way.  In fact, while this used to
be the sort of thing one could hack-up in simpler days, I think even
that would be a pain to try nowadays.

> When the array size has
>   a small upper bound:
>
> switch( arraysize )
> { case 0: printf( format ); break;
>   case 1: printf( format, 0[ array ]); break
>   case 2: printf( format, 0[ array ], 1[ array ]); break }

That won't work because the types will sometimes be wrong.
<snip>

To the OP: there's not portable way, and no simple implementation
specific way that I know of (but I am not up-to-date).

It's a huge pain to re-implement printf, but you can leverage printf to
do large parts of the work: scan the string printing non-format
characters.  When you see a % (not followed by %) scan to the end of the
format and pass that string to printf along with the next array element,
suitable converted.  That's very far from a good solution, but it may be
the best way in your case.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#94263

FromJames Harris <james.harris.1@gmail.com>
Date2016-09-29 21:23 +0100
Message-ID<nsjt7d$rgj$1@dont-email.me>
In reply to#94247
On 29/09/2016 17:13, Stefan Ram wrote:
> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>> When you want something like:
>> printf( "%d %d %d \n", $array );
>
>   When there is a limited set of conversion specifiers,
>   it does not seem too hard to write a custom array
>   print function. I just did it in five minutes:
>
> #include <stdio.h>
> #include <stdlib.h>
>
> void print
> ( char const * const restrict source,
>   int  const * const restrict array )
> { char const * p = source;
>   int  const * q = array;
>   int escape = 0; int looping = 1;
>   while( looping )
>   { char c = *p++;
>     if( !c )looping = 0; else
>     { if( escape )
>       { escape = 0;
>         switch( c )
>         { case 'd': printf( "%d", *q++ ); break; }}
>       else
>       { if( c == '%' )escape = 1; else
>         printf( "%c", c ); }}}}
>
> int main( void )
> { int array[] = { 1, 2, 3 };
>   print( "array = %d %d %d\n", array ); }
>
>   . Such a function must already have been written by other
>   persons before several times, so maybe you also can try to
>   search for such a function.

I expect I'll write something very like your code. The only thing I 
would add is if I scan by pointer instead of strtok then I could 
probably avoid the escape state. Other than that, it seems to be very 
much the way to go.

-- 
James Harris

[toc] | [prev] | [next] | [standalone]


#94265

FromBartC <bc@freeuk.com>
Date2016-09-29 22:03 +0100
Message-ID<nsjvj1$4c2$1@dont-email.me>
In reply to#94247
On 29/09/2016 17:13, Stefan Ram wrote:
> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>> When you want something like:
>> printf( "%d %d %d \n", $array );
>
>   When there is a limited set of conversion specifiers,
>   it does not seem too hard to write a custom array
>   print function. I just did it in five minutes:
>
> #include <stdio.h>
> #include <stdlib.h>
>
> void print
> ( char const * const restrict source,
>   int  const * const restrict array )
> { char const * p = source;
>   int  const * q = array;
>   int escape = 0; int looping = 1;
>   while( looping )
>   { char c = *p++;
>     if( !c )looping = 0; else
>     { if( escape )
>       { escape = 0;
>         switch( c )
>         { case 'd': printf( "%d", *q++ ); break; }}
>       else
>       { if( c == '%' )escape = 1; else
>         printf( "%c", c ); }}}}
>
> int main( void )
> { int array[] = { 1, 2, 3 };
>   print( "array = %d %d %d\n", array ); }

Even with a limited set of format specifiers, you will need %12d, %012d, 
%10.4f and so on. It's quite a bit of work. I don't know if this 
approach is worthwhile just for %d and %f and perhaps %s with no width, 
precision, or padding controls.

You might as well use printint() and printfloat(), or printintarray() as 
there is no longer a pressing reason to copy something like printf().

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#94268

FromJames Harris <james.harris.1@gmail.com>
Date2016-09-29 22:35 +0100
Message-ID<nsk1e9$ai1$1@dont-email.me>
In reply to#94265
On 29/09/2016 22:03, BartC wrote:
> On 29/09/2016 17:13, Stefan Ram wrote:
>> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>>> When you want something like:
>>> printf( "%d %d %d \n", $array );
>>
>>   When there is a limited set of conversion specifiers,
>>   it does not seem too hard to write a custom array
>>   print function. I just did it in five minutes:
>>
>> #include <stdio.h>
>> #include <stdlib.h>
>>
>> void print
>> ( char const * const restrict source,
>>   int  const * const restrict array )
>> { char const * p = source;
>>   int  const * q = array;
>>   int escape = 0; int looping = 1;
>>   while( looping )
>>   { char c = *p++;
>>     if( !c )looping = 0; else
>>     { if( escape )
>>       { escape = 0;
>>         switch( c )
>>         { case 'd': printf( "%d", *q++ ); break; }}
>>       else
>>       { if( c == '%' )escape = 1; else
>>         printf( "%c", c ); }}}}
>>
>> int main( void )
>> { int array[] = { 1, 2, 3 };
>>   print( "array = %d %d %d\n", array ); }
>
> Even with a limited set of format specifiers, you will need %12d, %012d,
> %10.4f and so on. It's quite a bit of work. I don't know if this
> approach is worthwhile just for %d and %f and perhaps %s with no width,
> precision, or padding controls.

Why not simply pass the format specifiers to snprintf?

If p points at the current % sign:

   written = snprintf(dest, size, p, args[i]);
   dest += written;

The only fiddly issue, AFAICS, is to increment p correctly past the 
format specifier.

-- 
James Harris

[toc] | [prev] | [next] | [standalone]


#94269

FromBartC <bc@freeuk.com>
Date2016-09-29 23:11 +0100
Message-ID<nsk3ic$kh3$1@dont-email.me>
In reply to#94268
On 29/09/2016 22:35, James Harris wrote:
> On 29/09/2016 22:03, BartC wrote:
>> On 29/09/2016 17:13, Stefan Ram wrote:
>>> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>>>> When you want something like:
>>>> printf( "%d %d %d \n", $array );
>>>
>>>   When there is a limited set of conversion specifiers,
>>>   it does not seem too hard to write a custom array
>>>   print function. I just did it in five minutes:
>>>
>>> #include <stdio.h>
>>> #include <stdlib.h>
>>>
>>> void print
>>> ( char const * const restrict source,
>>>   int  const * const restrict array )
>>> { char const * p = source;
>>>   int  const * q = array;
>>>   int escape = 0; int looping = 1;
>>>   while( looping )
>>>   { char c = *p++;
>>>     if( !c )looping = 0; else
>>>     { if( escape )
>>>       { escape = 0;
>>>         switch( c )
>>>         { case 'd': printf( "%d", *q++ ); break; }}
>>>       else
>>>       { if( c == '%' )escape = 1; else
>>>         printf( "%c", c ); }}}}
>>>
>>> int main( void )
>>> { int array[] = { 1, 2, 3 };
>>>   print( "array = %d %d %d\n", array ); }
>>
>> Even with a limited set of format specifiers, you will need %12d, %012d,
>> %10.4f and so on. It's quite a bit of work. I don't know if this
>> approach is worthwhile just for %d and %f and perhaps %s with no width,
>> precision, or padding controls.
>
> Why not simply pass the format specifiers to snprintf?
>
> If p points at the current % sign:
>
>   written = snprintf(dest, size, p, args[i]);
>   dest += written;
>
> The only fiddly issue, AFAICS, is to increment p correctly past the
> format specifier.

Well, that's the main problem! Getting snprintf to stop after the first 
format. If the format string is:

    "(%2d-%2d-%4d)"

and you start at the first "(", should it stop on (but not including) 
the first "-", or at the second "%"? And how to make it do that.

There might be some hairy methods of doing this: copying the format 
string, detecting the start of a format (first "%"), skipping to the 
start of the next "%", temporarily putting a null there, calling 
snprintf on the first bit, then restoring the second "%" and repeating 
with the next bit. With special handling for "%%" and for the last format.

Even there, there are some tricky formats, if you plan to deal with all 
of them, such as "%.*s" which requires /two/ operands, one for "*" and 
one for "s".

How many elements are there likely to be altogether? One easy workaround 
if you put an reasonable upper limit M is to just to do this:

  snprintf(dest,size,text,parms[0],parms[1],parms[2],...parms[M-1]);

The formatting will stop when it runs out of format codes. But there 
might still be issues if each parms[i] is 64 bits; on 32-bit targets 
(and I think you work with 16-bit ones too), it might expect arguments 
for %d formats to occupy 4 bytes on the stack not 8.

That's apart from this being inefficient (although that can be solved by 
using a switch with M different calls depending on the expected number 
of formats).

The stack problem might also be solvable, on 32-bits, by making parms[] 
a 32-bit array, and requiring 64-bit values to be split across two 
parms[] entries. But this makes it harder to work with parms[].

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#94320

FromJames Harris <james.harris.1@gmail.com>
Date2016-09-30 19:53 +0100
Message-ID<nsmcbv$2cc$1@dont-email.me>
In reply to#94269
On 29/09/2016 23:11, BartC wrote:
> On 29/09/2016 22:35, James Harris wrote:
>> On 29/09/2016 22:03, BartC wrote:

...

>>> Even with a limited set of format specifiers, you will need %12d, %012d,
>>> %10.4f and so on. It's quite a bit of work. I don't know if this
>>> approach is worthwhile just for %d and %f and perhaps %s with no width,
>>> precision, or padding controls.
>>
>> Why not simply pass the format specifiers to snprintf?
>>
>> If p points at the current % sign:
>>
>>   written = snprintf(dest, size, p, args[i]);
>>   dest += written;
>>
>> The only fiddly issue, AFAICS, is to increment p correctly past the
>> format specifier.
>
> Well, that's the main problem! Getting snprintf to stop after the first
> format.

Ah, yes. It will go on the the trailing null. In fact, assuming that the 
input string could be read only I would have to copy the format into a 
small buffer.

> If the format string is:
>
>    "(%2d-%2d-%4d)"
>
> and you start at the first "(", should it stop on (but not including)
> the first "-", or at the second "%"? And how to make it do that.

Why not:

- copy the literal "(" into the output
- copy "%2d" into a 'format buffer' and terminate it
- call snprintf using that buffer

and then repeat the process for the rest of the string?

> There might be some hairy methods of doing this: copying the format
> string, detecting the start of a format (first "%"), skipping to the
> start of the next "%", temporarily putting a null there, calling
> snprintf on the first bit, then restoring the second "%" and repeating
> with the next bit. With special handling for "%%" and for the last format.

If I omit the size checking for now, how about something like this:

   for (;;) { /* Each pair of non-format, format */

     /* Copy normal characters straight to the output buffer */
     while (*src != '%' && *src != '\0') {
       *dest++ = *src++;
     }
     if (*src == '\0') {
       break;
     }

     /* Copy the format string (starting with %) to a format buffer */
     format = format_buffer;
     *format++ = *src++;
     if (*src == '%') { /* If the source has %% */
       *dest++ = '%';
     }
     else { /* A single percent sign, i.e. starting a format spec */
       for (;;) { /* Until a terminating character */
         ch = *src++;
         if (ch == '\0') ....error....;
         *format++ = ch;
         if (ch ....is one of the terminating characters....) break;
       }
       *format = '\0';

       /* Format an argument */
       bytes = sprintf(dest, format, ....current arg ++....);
       dest += bytes;
     } /* end else */
   } /* end for */
   *dest = '\0';

Terminating chars: diouxXeEfFgGaAcsp%

> Even there, there are some tricky formats, if you plan to deal with all
> of them, such as "%.*s" which requires /two/ operands, one for "*" and
> one for "s".

Thanks. I wasn't aware of *. I knew I would have to reject n.

That points out another issue in that some format render differently on 
different architectures. That would be a pain. Given the complexities I 
may be better to accept only certain formats or even define my own. Grr. 
I'll think about it.

> How many elements are there likely to be altogether?

There's no arbitrary limit though the number would usually be small.


-- 
James Harris

[toc] | [prev] | [next] | [standalone]


#94326

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-30 20:53 +0100
Message-ID<87r3816u6r.fsf@bsb.me.uk>
In reply to#94320
James Harris <james.harris.1@gmail.com> writes:
<snip>

> If I omit the size checking for now, how about something like this:
>
>   for (;;) { /* Each pair of non-format, format */
>
>     /* Copy normal characters straight to the output buffer */
>     while (*src != '%' && *src != '\0') {
>       *dest++ = *src++;
>     }
>     if (*src == '\0') {
>       break;
>     }
>
>     /* Copy the format string (starting with %) to a format buffer */
>     format = format_buffer;
>     *format++ = *src++;
>     if (*src == '%') { /* If the source has %% */
>       *dest++ = '%';
>     }
>     else { /* A single percent sign, i.e. starting a format spec */
>       for (;;) { /* Until a terminating character */
>         ch = *src++;
>         if (ch == '\0') ....error....;
>         *format++ = ch;
>         if (ch ....is one of the terminating characters....) break;
>       }
>       *format = '\0';
>
>       /* Format an argument */
>       bytes = sprintf(dest, format, ....current arg ++....);

The trouble with this is that the type might be wrong.  I know you are
not aiming at totally portable code here, but there could be real
problems when there is a significant mismatch between the array member
type and the conversion specifier.  Worse, you may need to consider the
length modifier too.

>       dest += bytes;
>     } /* end else */
>   } /* end for */
>   *dest = '\0';
>
> Terminating chars: diouxXeEfFgGaAcsp%
>
>> Even there, there are some tricky formats, if you plan to deal with all
>> of them, such as "%.*s" which requires /two/ operands, one for "*" and
>> one for "s".

(and %*.*s which needs three)

> Thanks. I wasn't aware of *. I knew I would have to reject n.

I'm not sure why you must reject n.  It may not be useful in your
specific use case, but I think it should work with the above outline
like any other conversion.

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#94349

FromJames Harris <james.harris.1@gmail.com>
Date2016-10-01 09:08 +0100
Message-ID<nsnqsn$lsj$1@dont-email.me>
In reply to#94326
On 30/09/2016 20:53, Ben Bacarisse wrote:
> James Harris <james.harris.1@gmail.com> writes:
> <snip>
>
>> If I omit the size checking for now, how about something like this:
>>
>>   for (;;) { /* Each pair of non-format, format */
>>
>>     /* Copy normal characters straight to the output buffer */
>>     while (*src != '%' && *src != '\0') {
>>       *dest++ = *src++;
>>     }
>>     if (*src == '\0') {
>>       break;
>>     }
>>
>>     /* Copy the format string (starting with %) to a format buffer */
>>     format = format_buffer;
>>     *format++ = *src++;
>>     if (*src == '%') { /* If the source has %% */
>>       *dest++ = '%';
>>     }
>>     else { /* A single percent sign, i.e. starting a format spec */
>>       for (;;) { /* Until a terminating character */
>>         ch = *src++;
>>         if (ch == '\0') ....error....;
>>         *format++ = ch;
>>         if (ch ....is one of the terminating characters....) break;
>>       }
>>       *format = '\0';
>>
>>       /* Format an argument */
>>       bytes = sprintf(dest, format, ....current arg ++....);
>
> The trouble with this is that the type might be wrong.  I know you are
> not aiming at totally portable code here, but there could be real
> problems when there is a significant mismatch between the array member
> type and the conversion specifier.  Worse, you may need to consider the
> length modifier too.

That's always the case in C with varargs, isn't it?

I know some compilers can report type mismatches in the common case of a 
printf string literal and some args. But they cannot match in every 
case. The va_arg() macro has to have the expected type applied to it.


>>       dest += bytes;
>>     } /* end else */
>>   } /* end for */
>>   *dest = '\0';
>>
>> Terminating chars: diouxXeEfFgGaAcsp%
>>
>>> Even there, there are some tricky formats, if you plan to deal with all
>>> of them, such as "%.*s" which requires /two/ operands, one for "*" and
>>> one for "s".
>
> (and %*.*s which needs three)
>
>> Thanks. I wasn't aware of *. I knew I would have to reject n.
>
> I'm not sure why you must reject n.  It may not be useful in your
> specific use case, but I think it should work with the above outline
> like any other conversion.

It could be parsed. But for what I want to do there would be no sense in 
executing it.

I started down this road basically thinking to use snprintf as an easy 
way to plug rendered values into an error message. After all, it's built 
for just such an operation. And it is usually easier to use a built-in 
facility than writing one from scratch.

But given the complexities of the printf calls (arguments cannot come 
from memory, not all conversions supported on all versions of C, issues 
over value widths, not extendable, special conversions, no clear 
delimiter, etc) a custom solution might be better. It would be more to 
think about, and more to write. But possibly less work in the long run, 
and more flexible.

-- 
James Harris

[toc] | [prev] | [next] | [standalone]


#94360

FromBartC <bc@freeuk.com>
Date2016-10-01 11:15 +0100
Message-ID<nso2bv$b6j$1@dont-email.me>
In reply to#94349
On 01/10/2016 09:08, James Harris wrote:

> I started down this road basically thinking to use snprintf as an easy
> way to plug rendered values into an error message. After all, it's built
> for just such an operation. And it is usually easier to use a built-in
> facility than writing one from scratch.


I think using the a printf-style format string, while it may be 
attractive and familiar, is causing issues.

Perhaps use a different approach. For example, start with what you had:

   struct {
     char *text;         // "Error on line %04d in file \"%s\"\n"
     union any parms[];  // ({int}428, {char*}"file.c")
   };

The {int} etc indicate the implied type of the value in each union.

Now move the detailed formats to the unions (effectively, tag each union 
with the type of its value):

   struct {
     char *text;         // "Error on line # in file \"#\"\n"
     union any parms[];  // (("%04d",428), ("%s","file.c"))
   };

Here, I use "#" in the format string to make it very easy to scan. But a 
manual scan /is/ needed, and a printf-family function called separately 
for each individual item in the list. I don't think the scanning 
function needs to know or decipher the type - just pass the format, and 
the 64-bit union value, as they are.

The text in between and around the #s can be output by any means. ("%" 
can be used for this purpose, "#" was just to highlight the difference.)

To output an actual "#", then "##" could be used, or an ordinary single 
"#" that refers to a string "#" in the union array.

Alternatively, a parallel format array can be used to contain the format 
info:

   struct {
     char *text;         // "Error on line # in file \"#\"\n"
     char* formats[];  // ("%04d","%s")
     union any parms[];  // ({int}428, {char*}"file.c")
   };

(This can also solve the problem of codes such as "%.*s" as parms[] can 
then have extra elements (but end up being longer and out of step 
compared with formats[].)

(The above struct is probably not valid. You will either need bounded 
arrays in there, or pointers to array data stored elsewhere. However 
this is just an example.)

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#94435

FromJames Harris <james.harris.1@gmail.com>
Date2016-10-04 08:32 +0100
Message-ID<nsvltk$4ja$1@dont-email.me>
In reply to#94360
On 01/10/2016 11:15, BartC wrote:
> On 01/10/2016 09:08, James Harris wrote:
>
>> I started down this road basically thinking to use snprintf as an easy
>> way to plug rendered values into an error message. After all, it's built
>> for just such an operation. And it is usually easier to use a built-in
>> facility than writing one from scratch.
>
>
> I think using the a printf-style format string, while it may be
> attractive and familiar, is causing issues.
>
> Perhaps use a different approach. For example, start with what you had:
>
>   struct {
>     char *text;         // "Error on line %04d in file \"%s\"\n"
>     union any parms[];  // ({int}428, {char*}"file.c")
>   };
>
> The {int} etc indicate the implied type of the value in each union.
>
> Now move the detailed formats to the unions (effectively, tag each union
> with the type of its value):
>
>   struct {
>     char *text;         // "Error on line # in file \"#\"\n"
>     union any parms[];  // (("%04d",428), ("%s","file.c"))
>   };

Good idea. That seems more flexible overall, not just for this 
application. And it harks back to something we discussed before - 
separating knowledge of types from printing. Then the system-provided 
print routines don't have to know about all printable object types.

-- 
James Harris

[toc] | [prev] | [next] | [standalone]


#94361

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-10-01 11:15 +0100
Message-ID<87y4285q9a.fsf@bsb.me.uk>
In reply to#94349
James Harris <james.harris.1@gmail.com> writes:

> On 30/09/2016 20:53, Ben Bacarisse wrote:
>> James Harris <james.harris.1@gmail.com> writes:
>> <snip>
>>
>>> If I omit the size checking for now, how about something like this:
>>>
>>>   for (;;) { /* Each pair of non-format, format */
>>>
>>>     /* Copy normal characters straight to the output buffer */
>>>     while (*src != '%' && *src != '\0') {
>>>       *dest++ = *src++;
>>>     }
>>>     if (*src == '\0') {
>>>       break;
>>>     }
>>>
>>>     /* Copy the format string (starting with %) to a format buffer */
>>>     format = format_buffer;
>>>     *format++ = *src++;
>>>     if (*src == '%') { /* If the source has %% */
>>>       *dest++ = '%';
>>>     }
>>>     else { /* A single percent sign, i.e. starting a format spec */
>>>       for (;;) { /* Until a terminating character */
>>>         ch = *src++;
>>>         if (ch == '\0') ....error....;
>>>         *format++ = ch;
>>>         if (ch ....is one of the terminating characters....) break;
>>>       }
>>>       *format = '\0';
>>>
>>>       /* Format an argument */
>>>       bytes = sprintf(dest, format, ....current arg ++....);
>>
>> The trouble with this is that the type might be wrong.  I know you are
>> not aiming at totally portable code here, but there could be real
>> problems when there is a significant mismatch between the array member
>> type and the conversion specifier.  Worse, you may need to consider the
>> length modifier too.
>
> That's always the case in C with varargs, isn't it?
>
> I know some compilers can report type mismatches in the common case of
> a printf string literal and some args. But they cannot match in every
> case. The va_arg() macro has to have the expected type applied to it.

I didn't mean that the user has passed the wrong type -- there's nothing
you can do about that -- I meant the type of whatever "current arg ++"
denotes could be wrong.  You suggested that the array might be a union,
but there is no guarantee that passing a union object will work.  On
some systems (probably little-endian ones) it might just work (though
not for single-precision float), but it's always going to be
non-portable.

>>>       dest += bytes;
>>>     } /* end else */
>>>   } /* end for */
>>>   *dest = '\0';
>>>
>>> Terminating chars: diouxXeEfFgGaAcsp%
>>>
>>>> Even there, there are some tricky formats, if you plan to deal with all
>>>> of them, such as "%.*s" which requires /two/ operands, one for "*" and
>>>> one for "s".
>>
>> (and %*.*s which needs three)
>>
>>> Thanks. I wasn't aware of *. I knew I would have to reject n.
>>
>> I'm not sure why you must reject n.  It may not be useful in your
>> specific use case, but I think it should work with the above outline
>> like any other conversion.
>
> It could be parsed. But for what I want to do there would be no sense
> in executing it.
>
> I started down this road basically thinking to use snprintf as an easy
> way to plug rendered values into an error message. After all, it's
> built for just such an operation. And it is usually easier to use a
> built-in facility than writing one from scratch.

Can I just check that the 'v' version of the function are not what you
want?  The description here does not explain why the data are in an
array of some union type and some people are unaware of them.

> But given the complexities of the printf calls (arguments cannot come
> from memory, not all conversions supported on all versions of C,
> issues over value widths, not extendable, special conversions, no
> clear delimiter, etc) a custom solution might be better. It would be
> more to think about, and more to write. But possibly less work in the
> long run, and more flexible.

Very likely.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#94434

FromJames Harris <james.harris.1@gmail.com>
Date2016-10-04 08:28 +0100
Message-ID<nsvlm7$3r7$1@dont-email.me>
In reply to#94361
On 01/10/2016 11:15, Ben Bacarisse wrote:
> James Harris <james.harris.1@gmail.com> writes:
>
>> On 30/09/2016 20:53, Ben Bacarisse wrote:
>>> James Harris <james.harris.1@gmail.com> writes:
>>> <snip>
>>>
>>>> If I omit the size checking for now, how about something like this:
>>>>
>>>>   for (;;) { /* Each pair of non-format, format */
>>>>
>>>>     /* Copy normal characters straight to the output buffer */
>>>>     while (*src != '%' && *src != '\0') {
>>>>       *dest++ = *src++;
>>>>     }
>>>>     if (*src == '\0') {
>>>>       break;
>>>>     }
>>>>
>>>>     /* Copy the format string (starting with %) to a format buffer */
>>>>     format = format_buffer;
>>>>     *format++ = *src++;
>>>>     if (*src == '%') { /* If the source has %% */
>>>>       *dest++ = '%';
>>>>     }
>>>>     else { /* A single percent sign, i.e. starting a format spec */
>>>>       for (;;) { /* Until a terminating character */
>>>>         ch = *src++;
>>>>         if (ch == '\0') ....error....;
>>>>         *format++ = ch;
>>>>         if (ch ....is one of the terminating characters....) break;
>>>>       }
>>>>       *format = '\0';
>>>>
>>>>       /* Format an argument */
>>>>       bytes = sprintf(dest, format, ....current arg ++....);
>>>
>>> The trouble with this is that the type might be wrong.  I know you are
>>> not aiming at totally portable code here, but there could be real
>>> problems when there is a significant mismatch between the array member
>>> type and the conversion specifier.  Worse, you may need to consider the
>>> length modifier too.
>>
>> That's always the case in C with varargs, isn't it?
>>
>> I know some compilers can report type mismatches in the common case of
>> a printf string literal and some args. But they cannot match in every
>> case. The va_arg() macro has to have the expected type applied to it.
>
> I didn't mean that the user has passed the wrong type -- there's nothing
> you can do about that -- I meant the type of whatever "current arg ++"
> denotes could be wrong.

I meant advancing a pointer along the argument array. I should have 
explained it.

> You suggested that the array might be a union,
> but there is no guarantee that passing a union object will work.  On
> some systems (probably little-endian ones) it might just work (though
> not for single-precision float), but it's always going to be
> non-portable.

It would have been an array where each element was a union. So no 
problem with endianness etc.


>>>       dest += bytes;
>>>>     } /* end else */
>>>>   } /* end for */
>>>>   *dest = '\0';
>>>>
>>>> Terminating chars: diouxXeEfFgGaAcsp%
>>>>
>>>>> Even there, there are some tricky formats, if you plan to deal with all
>>>>> of them, such as "%.*s" which requires /two/ operands, one for "*" and
>>>>> one for "s".
>>>
>>> (and %*.*s which needs three)
>>>
>>>> Thanks. I wasn't aware of *. I knew I would have to reject n.
>>>
>>> I'm not sure why you must reject n.  It may not be useful in your
>>> specific use case, but I think it should work with the above outline
>>> like any other conversion.
>>
>> It could be parsed. But for what I want to do there would be no sense
>> in executing it.
>>
>> I started down this road basically thinking to use snprintf as an easy
>> way to plug rendered values into an error message. After all, it's
>> built for just such an operation. And it is usually easier to use a
>> built-in facility than writing one from scratch.
>
> Can I just check that the 'v' version of the function are not what you
> want?  The description here does not explain why the data are in an
> array of some union type and some people are unaware of them.

Good question but the data are stored in memory so the v versions are 
not an option.


-- 
James Harris

[toc] | [prev] | [next] | [standalone]


#94439

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-10-04 09:49 +0100
Message-ID<87fuoc33dx.fsf@bsb.me.uk>
In reply to#94434
James Harris <james.harris.1@gmail.com> writes:

> On 01/10/2016 11:15, Ben Bacarisse wrote:
>> James Harris <james.harris.1@gmail.com> writes:
>>
>>> On 30/09/2016 20:53, Ben Bacarisse wrote:
>>>> James Harris <james.harris.1@gmail.com> writes:
>>>> <snip>
>>>>
>>>>> If I omit the size checking for now, how about something like this:
>>>>>
>>>>>   for (;;) { /* Each pair of non-format, format */
>>>>>
>>>>>     /* Copy normal characters straight to the output buffer */
>>>>>     while (*src != '%' && *src != '\0') {
>>>>>       *dest++ = *src++;
>>>>>     }
>>>>>     if (*src == '\0') {
>>>>>       break;
>>>>>     }
>>>>>
>>>>>     /* Copy the format string (starting with %) to a format buffer */
>>>>>     format = format_buffer;
>>>>>     *format++ = *src++;
>>>>>     if (*src == '%') { /* If the source has %% */
>>>>>       *dest++ = '%';
>>>>>     }
>>>>>     else { /* A single percent sign, i.e. starting a format spec */
>>>>>       for (;;) { /* Until a terminating character */
>>>>>         ch = *src++;
>>>>>         if (ch == '\0') ....error....;
>>>>>         *format++ = ch;
>>>>>         if (ch ....is one of the terminating characters....) break;
>>>>>       }
>>>>>       *format = '\0';
>>>>>
>>>>>       /* Format an argument */
>>>>>       bytes = sprintf(dest, format, ....current arg ++....);
>>>>
>>>> The trouble with this is that the type might be wrong.  I know you are
>>>> not aiming at totally portable code here, but there could be real
>>>> problems when there is a significant mismatch between the array member
>>>> type and the conversion specifier.  Worse, you may need to consider the
>>>> length modifier too.
>>>
>>> That's always the case in C with varargs, isn't it?
>>>
>>> I know some compilers can report type mismatches in the common case of
>>> a printf string literal and some args. But they cannot match in every
>>> case. The va_arg() macro has to have the expected type applied to it.
>>
>> I didn't mean that the user has passed the wrong type -- there's nothing
>> you can do about that -- I meant the type of whatever "current arg ++"
>> denotes could be wrong.
>
> I meant advancing a pointer along the argument array. I should have
> explained it.

Yes, I got that bit -- the ++ was clear enough.  That's not the point I
am making but I am running out of ways to make it so I suspect there is
some basic disagreement between us here, maybe about what types are in
C.

>> You suggested that the array might be a union,
>> but there is no guarantee that passing a union object will work.  On
>> some systems (probably little-endian ones) it might just work (though
>> not for single-precision float), but it's always going to be
>> non-portable.
>
> It would have been an array where each element was a union. So no
> problem with endianness etc.

The mechanism that is used to pass a union may not work the for all the
types that union might contain.  Take an imaginary example where int are
passed by pushing two bytes onto the stack and long by pushing four.
The %d format will use the the "next" two bytes and %ld will use the
next four.  Passing a union of an int and long will have to push four
bytes but whether the "next" two correspond to the short in the union
depends on endianness.

But there are very many other possible problems that come does to one
basic problem.  If the format has "%d" the corresponding argument must
be an int and not a union that might contain an int.

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#94440

FromBartC <bc@freeuk.com>
Date2016-10-04 11:43 +0100
Message-ID<nt013r$961$1@dont-email.me>
In reply to#94439
On 04/10/2016 09:49, Ben Bacarisse wrote:
> James Harris <james.harris.1@gmail.com> writes:

>> It would have been an array where each element was a union. So no
>> problem with endianness etc.
>
> The mechanism that is used to pass a union may not work the for all the
> types that union might contain.  Take an imaginary example where int are
> passed by pushing two bytes onto the stack and long by pushing four.
> The %d format will use the the "next" two bytes and %ld will use the
> next four.  Passing a union of an int and long will have to push four
> bytes but whether the "next" two correspond to the short in the union
> depends on endianness.

union {
    uint32_t u32;
    uint64_t u64;
} u;

Assuming big-endian, then:

   u.u64 = 0x1234_5678;

will result in a 16-bit memory layout of:

   (0x1234, 0x5678)     memory addresses increasing left-to-right

inside the union. And the same layout when pushed onto a stack (when it 
isn't just passed in a register anyway).

For 32 bits, then:

   u.u32 = 0x2016;

will result in the layout (0x2016, 0x????). When pushed (by always 
passing u.u64 rather than the whole union u), the stack layout will 
still have 0x2016 first.

The main problem would be with passing two arguments for "%d %d", then 
passing two ints like this means they are 8 bytes apart rather than 4. 
But it might be workable for a single argument at a time.

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#94441

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-10-04 13:42 +0100
Message-ID<874m4s2smc.fsf@bsb.me.uk>
In reply to#94440
BartC <bc@freeuk.com> writes:

> On 04/10/2016 09:49, Ben Bacarisse wrote:
>> James Harris <james.harris.1@gmail.com> writes:
>
>>> It would have been an array where each element was a union. So no
>>> problem with endianness etc.
>>
>> The mechanism that is used to pass a union may not work the for all the
>> types that union might contain.  Take an imaginary example where int are
>> passed by pushing two bytes onto the stack and long by pushing four.
>> The %d format will use the the "next" two bytes and %ld will use the
>> next four.  Passing a union of an int and long will have to push four
>> bytes but whether the "next" two correspond to the short in the union
>> depends on endianness.
>
> union {
>    uint32_t u32;
>    uint64_t u64;
> } u;
>
> Assuming big-endian, then:
>
>   u.u64 = 0x1234_5678;
>
> will result in a 16-bit memory layout of:
>
>   (0x1234, 0x5678)     memory addresses increasing left-to-right
>
> inside the union. And the same layout when pushed onto a stack (when
> it isn't just passed in a register anyway).
>
> For 32 bits, then:
>
>   u.u32 = 0x2016;
>
> will result in the layout (0x2016, 0x????). When pushed (by always
> passing u.u64 rather than the whole union u), the stack layout will
> still have 0x2016 first.

I should have stuck with my first thought -- short and int.  The format
for short (%hd) must assume that the short has been promoted by the
default argument conversions.  That won't happen when the union is
pushed.  That will probably work on a little-endian system, hence by
original remark about that.

> The main problem would be with passing two arguments for "%d %d", then
> passing two ints like this means they are 8 bytes apart rather than
> 4. But it might be workable for a single argument at a time.

Actually the main problem is simply that type is wrong.  I should
probably not have tried to come up with a specific example, because the
problem is more general than any one potential pitfall.  Once you you've
lied the compiler, you are its mercy.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#94442

FromBartC <bc@freeuk.com>
Date2016-10-04 14:03 +0100
Message-ID<nt09b2$5vc$1@dont-email.me>
In reply to#94441
On 04/10/2016 13:42, Ben Bacarisse wrote:
> BartC <bc@freeuk.com> writes:

>> The main problem would be with passing two arguments for "%d %d", then
>> passing two ints like this means they are 8 bytes apart rather than
>> 4. But it might be workable for a single argument at a time.
>
> Actually the main problem is simply that type is wrong.  I should
> probably not have tried to come up with a specific example, because the
> problem is more general than any one potential pitfall.  Once you you've
> lied the compiler, you are its mercy.

This is for a variadic argument, so the type cannot be wrong, as it's 
not specified! (Except inside the printf implementation, but then that's 
not a compiler issue.)

Nonetheless there is another type-related problem with this: some 
machines pass the first few arguments in registers, but floating point 
arguments might use different registers. So on x64, a double might be 
passed in both rcx and xmm0 when it is for a variadic function, rather 
than just rcx.

You might get around that by always pushing a double member of a union 
instead of uint64_t, but it starts looking more dodgy.

Better here to find out what type is needed and pass the correct member 
of the union using conditional code. But that would still be limited to 
a single operand of printf per call.

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#94443

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-10-04 14:16 +0100
Message-ID<87pong1cgk.fsf@bsb.me.uk>
In reply to#94442
BartC <bc@freeuk.com> writes:

> On 04/10/2016 13:42, Ben Bacarisse wrote:
>> BartC <bc@freeuk.com> writes:
>
>>> The main problem would be with passing two arguments for "%d %d", then
>>> passing two ints like this means they are 8 bytes apart rather than
>>> 4. But it might be workable for a single argument at a time.
>>
>> Actually the main problem is simply that type is wrong.  I should
>> probably not have tried to come up with a specific example, because the
>> problem is more general than any one potential pitfall.  Once you you've
>> lied the compiler, you are its mercy.
>
> This is for a variadic argument, so the type cannot be wrong, as it's
> not specified! (Except inside the printf implementation, but then
> that's not a compiler issue.)

No, the type is specified by the format.  An argument of the wrong
(promoted) type gives undefined behaviour just a surely as passing the
wrong type to any other function.  Though the wording is rather strict,
the standard intends to offer a little leeway, I think, in that it
defines some groups of types as having the same size and representation
for the purposes being passed to variadic functions.

> Nonetheless there is another type-related problem with this: some
> machines pass the first few arguments in registers, but floating point
> arguments might use different registers. So on x64, a double might be
> passed in both rcx and xmm0 when it is for a variadic function, rather
> than just rcx.

That's one of the consequences of passing the wrong type.

> You might get around that by always pushing a double member of a union
> instead of uint64_t, but it starts looking more dodgy.
>
> Better here to find out what type is needed and pass the correct
> member of the union using conditional code. But that would still be
> limited to a single operand of printf per call.

That would work (I think I suggested it when I brought up the problem,
though I may have edited it away -- I certainly wrote-up that solution!)
but it's so messy (since you need the length specifier as well) that
it's really looking less and less like the right solution.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#94450

FromJames Harris <james.harris.1@gmail.com>
Date2016-10-04 20:01 +0100
Message-ID<nt0ua3$kcf$1@dont-email.me>
In reply to#94439
On 04/10/2016 09:49, Ben Bacarisse wrote:
> James Harris <james.harris.1@gmail.com> writes:
>
>> On 01/10/2016 11:15, Ben Bacarisse wrote:
>>> James Harris <james.harris.1@gmail.com> writes:
>>>
>>>> On 30/09/2016 20:53, Ben Bacarisse wrote:
>>>>> James Harris <james.harris.1@gmail.com> writes:
>>>>> <snip>
>>>>>
>>>>>> If I omit the size checking for now, how about something like this:
>>>>>>
>>>>>>   for (;;) { /* Each pair of non-format, format */
>>>>>>
>>>>>>     /* Copy normal characters straight to the output buffer */
>>>>>>     while (*src != '%' && *src != '\0') {
>>>>>>       *dest++ = *src++;
>>>>>>     }
>>>>>>     if (*src == '\0') {
>>>>>>       break;
>>>>>>     }
>>>>>>
>>>>>>     /* Copy the format string (starting with %) to a format buffer */
>>>>>>     format = format_buffer;
>>>>>>     *format++ = *src++;
>>>>>>     if (*src == '%') { /* If the source has %% */
>>>>>>       *dest++ = '%';
>>>>>>     }
>>>>>>     else { /* A single percent sign, i.e. starting a format spec */
>>>>>>       for (;;) { /* Until a terminating character */
>>>>>>         ch = *src++;
>>>>>>         if (ch == '\0') ....error....;
>>>>>>         *format++ = ch;
>>>>>>         if (ch ....is one of the terminating characters....) break;
>>>>>>       }
>>>>>>       *format = '\0';
>>>>>>
>>>>>>       /* Format an argument */
>>>>>>       bytes = sprintf(dest, format, ....current arg ++....);
>>>>>
>>>>> The trouble with this is that the type might be wrong.  I know you are
>>>>> not aiming at totally portable code here, but there could be real
>>>>> problems when there is a significant mismatch between the array member
>>>>> type and the conversion specifier.  Worse, you may need to consider the
>>>>> length modifier too.
>>>>
>>>> That's always the case in C with varargs, isn't it?
>>>>
>>>> I know some compilers can report type mismatches in the common case of
>>>> a printf string literal and some args. But they cannot match in every
>>>> case. The va_arg() macro has to have the expected type applied to it.
>>>
>>> I didn't mean that the user has passed the wrong type -- there's nothing
>>> you can do about that -- I meant the type of whatever "current arg ++"
>>> denotes could be wrong.
>>
>> I meant advancing a pointer along the argument array. I should have
>> explained it.
>
> Yes, I got that bit -- the ++ was clear enough.  That's not the point I
> am making but I am running out of ways to make it so I suspect there is
> some basic disagreement between us here, maybe about what types are in
> C.

Response below (assuming it's the same point).

>>> You suggested that the array might be a union,
>>> but there is no guarantee that passing a union object will work.  On
>>> some systems (probably little-endian ones) it might just work (though
>>> not for single-precision float), but it's always going to be
>>> non-portable.
>>
>> It would have been an array where each element was a union. So no
>> problem with endianness etc.
>
> The mechanism that is used to pass a union may not work the for all the
> types that union might contain.  Take an imaginary example where int are
> passed by pushing two bytes onto the stack and long by pushing four.
> The %d format will use the the "next" two bytes and %ld will use the
> next four.  Passing a union of an int and long will have to push four
> bytes but whether the "next" two correspond to the short in the union
> depends on endianness.
>
> But there are very many other possible problems that come does to one
> basic problem.  If the format has "%d" the corresponding argument must
> be an int and not a union that might contain an int.

So if I had

   union any {
     int16_t i16;
     int i;
     double d;
   } u;

I guess you are saying that the code to work with "%d" would have to 
refer to u.i instead of u?


-- 
James Harris

[toc] | [prev] | [next] | [standalone]


Page 1 of 3  [1] 2 3  Next page →

Back to top | Article view | comp.lang.c


csiph-web