Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #94244 > unrolled thread
| Started by | James Harris <james.harris.1@gmail.com> |
|---|---|
| First post | 2016-09-29 16:20 +0100 |
| Last post | 2016-10-02 21:27 +0200 |
| Articles | 20 on this page of 44 — 9 participants |
Back to article view | Back to comp.lang.c
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 →
| From | James Harris <james.harris.1@gmail.com> |
|---|---|
| Date | 2016-09-29 16:20 +0100 |
| Subject | When 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]
| From | James Harris <james.harris.1@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-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]
| From | James Harris <james.harris.1@gmail.com> |
|---|---|
| Date | 2016-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]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-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]
| From | James Harris <james.harris.1@gmail.com> |
|---|---|
| Date | 2016-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]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-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]
| From | James Harris <james.harris.1@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-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]
| From | James Harris <james.harris.1@gmail.com> |
|---|---|
| Date | 2016-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]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-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]
| From | James Harris <james.harris.1@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-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]
| From | James Harris <james.harris.1@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-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]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-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]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-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]
| From | James Harris <james.harris.1@gmail.com> |
|---|---|
| Date | 2016-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