473,221 Members | 1,971 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,221 software developers and data experts.

printf with run-time format strings

Hello,

I have the following structure:

struct foo {
char *format; /* format string to be used with printf() */
int nparm; /* number of %d specifiers in the format string */
/* 0 <= nparm <= 4 */
};

e.g.

struct foo bar = { "foo %d %d bar %d\n", 3 };

I can write:

printf(bar.format, rand(), rand(), rand());

Assume I have a properly initialized array of struct foo:

struct foo array[100]; ... /* initialize array */

and I want to print every struct foo. Do I have to make a special case
for every possible value of nparm? As in:

for (i=0; i < 100; ++i)
{
switch(array[i].parm)
{
case 0:
printf(array[i].format); break;
case 1:
printf(array[i].format, rand()); break;
...
case 4:
printf(array[i].format, rand(), rand(), rand(), rand()); break;
}
}

Isn't there a better way? If I think in terms of a stack (which I know
is a sin in c.l.c.) I should be able to push however many parameters I
have onto the stack, push either the number of arguments or NULL (I'm
not sure how printf works) and then jump to the the printf code.

I've never used variadic functions. Could they prove useful in this case?

Regards,

Grumble

Nov 14 '05 #1
11 5898
Grumble <in*****@kma.eu.org> wrote:
I have the following structure:

struct foo {
char *format; /* format string to be used with printf() */
int nparm; /* number of %d specifiers in the format string */
/* 0 <= nparm <= 4 */
};

e.g.

struct foo bar = { "foo %d %d bar %d\n", 3 };

I can write:

printf(bar.format, rand(), rand(), rand());
Yes. Note that you don't know in which order the rand()s are called.
With rand(), this is obviously not of great importance, but if you
substitute a function which pops a value from a stack instead, you might
be in for a surprise...
Assume I have a properly initialized array of struct foo:

struct foo array[100]; ... /* initialize array */

and I want to print every struct foo. Do I have to make a special case
for every possible value of nparm? As in:

for (i=0; i < 100; ++i)
{
switch(array[i].parm)
{
case 0:
printf(array[i].format); break;
case 1:
printf(array[i].format, rand()); break;
...
case 4:
printf(array[i].format, rand(), rand(), rand(), rand()); break;
}
}
You do if you really need to use printf(). If you know in advance that
the maximum number of parameters is limited, this isn't such a bad
approach.
Isn't there a better way? If I think in terms of a stack (which I know
is a sin in c.l.c.)
You know nothing of the sort. Why would using stacks be a sin? What you
can't do in ISO C is use any kind of system, hardware or program stack,
but there's nothing to prevent you from creating your own stack ADT.
I should be able to push however many parameters I
have onto the stack, push either the number of arguments or NULL (I'm
not sure how printf works) and then jump to the the printf code.
Ah, well, _that_ is impossible. printf() doesn't know how to use your
stack, and you can't interfere with its stack. I wouldn't even try if
you could, either; much too risky.
I've never used variadic functions.
(Yes, you have; printf() is one.)
Could they prove useful in this case?


Not that I can see. <stdarg.h> is for writing functions that get
variable numbers of arguments passed to them, not for passing variable
numbers of arguments to other functions. It would have been useful had
that been possible, but alas, it isn't.

Richard
Nov 14 '05 #2
"Grumble" <in*****@kma.eu.org> wrote in message
news:c0**********@news-rocq.inria.fr...
Hello,

I have the following structure:

struct foo {
char *format; /* format string to be used with printf() */
int nparm; /* number of %d specifiers in the format string */
/* 0 <= nparm <= 4 */
};

e.g.

struct foo bar = { "foo %d %d bar %d\n", 3 };

I can write:

printf(bar.format, rand(), rand(), rand());

Assume I have a properly initialized array of struct foo:

struct foo array[100]; ... /* initialize array */

and I want to print every struct foo. Do I have to make a special case
for every possible value of nparm? As in:

for (i=0; i < 100; ++i)
{
switch(array[i].parm)
{
case 0:
printf(array[i].format); break;
case 1:
printf(array[i].format, rand()); break;
...
case 4:
printf(array[i].format, rand(), rand(), rand(), rand()); break;
}
}

Isn't there a better way? If I think in terms of a stack (which I know
is a sin in c.l.c.) I should be able to push however many parameters I
have onto the stack, push either the number of arguments or NULL (I'm
not sure how printf works) and then jump to the the printf code.

I've never used variadic functions. Could they prove useful in this case?

Regards,

Grumble

Well as you said, you can write your own function that behaves like printf()
and takes its parameter list in the form of a linked list or any other mean
that can be fed during runtime.

If you still want to use printf(), and on Intel x86, you can push your own
parameters to the stack in a for loop.
By observing the assembly output of a normal printf() call you can
understand how to pass extra parameters in runtime as if they were added by
the compiler.

--
Elias
Nov 14 '05 #3


Grumble wrote:
Hello,

I have the following structure:

struct foo {
char *format; /* format string to be used with printf() */
int nparm; /* number of %d specifiers in the format string */
/* 0 <= nparm <= 4 */
};

e.g.

struct foo bar = { "foo %d %d bar %d\n", 3 };

I can write:

printf(bar.format, rand(), rand(), rand());

Assume I have a properly initialized array of struct foo:

struct foo array[100]; ... /* initialize array */

and I want to print every struct foo. Do I have to make a special case
for every possible value of nparm? As in:

for (i=0; i < 100; ++i)
{
switch(array[i].parm)
{
case 0:
printf(array[i].format); break;
case 1:
printf(array[i].format, rand()); break;
...
case 4:
printf(array[i].format, rand(), rand(), rand(), rand()); break;
}
}

Isn't there a better way? If I think in terms of a stack (which I know
is a sin in c.l.c.) I should be able to push however many parameters I
have onto the stack, push either the number of arguments or NULL (I'm
not sure how printf works) and then jump to the the printf code.


I am not sure if it is a better way but you can make a macro of
the last printf arguments. If there are more arguments than there
are specifiers, the remaining arguments are evaluated but otherwise
ignored.

#define ARGS rand(),rand(),rand(),rand() /* max of 4 args */

Then you printf would look this this:
printf(array.format,ARGS);

Example:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define ARGS rand(),rand(),rand(),rand()

struct foo {
char *format; /* format string to be used with printf() */
unsigned nparm; /* number of %d specifiers in the format string */
/* 0 <= nparm <= 4 */
};

struct foo addFoo(const char *format);

int main(void)
{
struct foo myfoo = addFoo("this is %d and this is %d");
if(myfoo.format) printf(myfoo.format,ARGS);
free(myfoo.format);
return 0;
}

struct foo addFoo(const char *format)
{ /* TODO Add code to make sure "%d" */
struct foo tmp = {NULL};
const char *cs;
unsigned cnt;
size_t len = strlen(format);

for(cnt = 0,cs = format; (cs = strchr(cs,'%')); cs+=1,cnt++) ;
if(cnt <= 4 && len) tmp.format = malloc(len+2);
if(tmp.format)
{
strcpy(tmp.format,format);
tmp.nparm = cnt;
if('\n' != tmp.format[strlen(tmp.format)-1])
strcat(tmp.format,"\n");
}
return tmp;
}


--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #4
Al Bowers <xa******@rapidsys.com> wrote:
Grumble wrote:
for (i=0; i < 100; ++i)
{
switch(array[i].parm)
{
case 0:
printf(array[i].format); break;
case 1:
printf(array[i].format, rand()); break;
...
case 4:
printf(array[i].format, rand(), rand(), rand(), rand()); break;
}
}
I am not sure if it is a better way but you can make a macro of
the last printf arguments. If there are more arguments than there
are specifiers, the remaining arguments are evaluated but otherwise
ignored.

#define ARGS rand(),rand(),rand(),rand() /* max of 4 args */


Of course! Should've thought of that... You don't even need to make a
macro of it; putting them all into the function call works just as well.
OTOH, it only works as desired if the arguments do not have side effects
or if (as with rand()) its side effects are not likely to be important
anyway.
Then you printf would look this this:
printf(array.format,ARGS);


Or simply

printf(array[i].format, rand(), rand(), rand(), rand());

with a comment explaining that printf() will ignore the superfluous
parameters, if necessary.

Richard
Nov 14 '05 #5
Richard Bos wrote:
Al Bowers <xa******@rapidsys.com> wrote:
Grumble wrote:
for (i=0; i < 100; ++i)
{
switch(array[i].parm)
{
case 0:
printf(array[i].format); break;
case 1:
printf(array[i].format, rand()); break;
...
case 4:
printf(array[i].format, rand(), rand(), rand(), rand()); break;
}
}


I am not sure if it is a better way but you can make a macro of
the last printf arguments. If there are more arguments than there
are specifiers, the remaining arguments are evaluated but otherwise
ignored.

#define ARGS rand(),rand(),rand(),rand() /* max of 4 args */

Of course! Should've thought of that... You don't even need to make a
macro of it; putting them all into the function call works just as well.
OTOH, it only works as desired if the arguments do not have side effects
or if (as with rand()) its side effects are not likely to be important
anyway.

Then you printf would look this this:
printf(array.format,ARGS);

Or simply

printf(array[i].format, rand(), rand(), rand(), rand());

with a comment explaining that printf() will ignore the superfluous
parameters, if necessary.


What if I wanted to print values from an array instead of calling rand()?

printf(array[i].format, v[0], v[1], v[2], v[3]);

If v was defined as int v[3]; then I suppose the above would yield UB?

What if I had 4 variables: int v1, v2, v3, v4;

printf(array[i].format, v1, v2, v3, v4);

If v4 was uninitialized but also not used by printf, would the above
yield UB?

Regards,

Grumble

Nov 14 '05 #6
On Tue, 10 Feb 2004 17:54:05 +0100, Grumble <in*****@kma.eu.org> wrote
in comp.lang.c:
Richard Bos wrote:
Al Bowers <xa******@rapidsys.com> wrote:
Grumble wrote:

for (i=0; i < 100; ++i)
{
switch(array[i].parm)
{
case 0:
printf(array[i].format); break;
case 1:
printf(array[i].format, rand()); break;
...
case 4:
printf(array[i].format, rand(), rand(), rand(), rand()); break;
}
}

I am not sure if it is a better way but you can make a macro of
the last printf arguments. If there are more arguments than there
are specifiers, the remaining arguments are evaluated but otherwise
ignored.

#define ARGS rand(),rand(),rand(),rand() /* max of 4 args */

Of course! Should've thought of that... You don't even need to make a
macro of it; putting them all into the function call works just as well.
OTOH, it only works as desired if the arguments do not have side effects
or if (as with rand()) its side effects are not likely to be important
anyway.

Then you printf would look this this:
printf(array.format,ARGS);

Or simply

printf(array[i].format, rand(), rand(), rand(), rand());

with a comment explaining that printf() will ignore the superfluous
parameters, if necessary.


What if I wanted to print values from an array instead of calling rand()?

printf(array[i].format, v[0], v[1], v[2], v[3]);

If v was defined as int v[3]; then I suppose the above would yield UB?


You are correct, sir.
What if I had 4 variables: int v1, v2, v3, v4;

printf(array[i].format, v1, v2, v3, v4);

If v4 was uninitialized but also not used by printf, would the above
yield UB?
Yes it would, in theory. The act of passing v4 by value requires the
compiler to generate code to read an int value from that object, and
reading an uninitialized value is UB. There is one possible int value
that could be a trap representation, neglecting padding bits which
frankly need to be neglected.

But you could do this:

int int_args [3] = { 0 }; /* in a function, initializes every time */

And in some cases:

memcpy(&int_args[0], &v[0], 3 * sizeof *int_args);

(& and [0] added for example clarity), then:

printf(fmt, int_args[0], int_args[1], ...
Regards,

Grumble


--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #7
Grumble <in*****@kma.eu.org> wrote:
Richard Bos wrote:
Or simply

printf(array[i].format, rand(), rand(), rand(), rand());

with a comment explaining that printf() will ignore the superfluous
parameters, if necessary.


What if I wanted to print values from an array instead of calling rand()?

printf(array[i].format, v[0], v[1], v[2], v[3]);

If v was defined as int v[3]; then I suppose the above would yield UB?

What if I had 4 variables: int v1, v2, v3, v4;

printf(array[i].format, v1, v2, v3, v4);

If v4 was uninitialized but also not used by printf, would the above
yield UB?


Yes and yes, but in the latter case this can be avoided by simply
initialising the objects to some dummy value, and in the former case you
may be able to declare the array larger than strictly necessary, or to
copy it into a temporary array of the right size.

Richard
Nov 14 '05 #8
Richard Bos wrote:
Grumble wrote:
Richard Bos wrote:
Or simply

printf(array[i].format, rand(), rand(), rand(), rand());

with a comment explaining that printf() will ignore the
superfluous parameters, if necessary.


What if I wanted to print values from an array instead of calling
rand()?

printf(array[i].format, v[0], v[1], v[2], v[3]);

If v was defined as int v[3]; then I suppose the above would
yield UB?

What if I had 4 variables: int v1, v2, v3, v4;

printf(array[i].format, v1, v2, v3, v4);

If v4 was uninitialized but also not used by printf, would the
above yield UB?


Yes and yes, but in the latter case this can be avoided by simply
initialising the objects to some dummy value, and in the former
case you may be able to declare the array larger than strictly
necessary, or to copy it into a temporary array of the right size.


Thanks to all for your precious help!

Bonus question :-)

Assume I want to make the array size a compile-time constant:

#define MAXPARM 8 /* for example */

Is there a way to write a clever macro that would expand to v[0],
v[1], ..., v[MAXPARM-1] whatever the value of MAXPARM? (If it helps,
you can assume MAXPARM will never be greater than 100.)

Then I could write:

int v[MAXPARM] = {0};
/* initialize v[0], ..., v[k] where k<MAXPARM */
printf(format, SMART_MACRO(v));

--
Regards,

Grumble

Nov 14 '05 #9
Grumble <in*****@kma.eu.org> wrote:
Bonus question :-)

Assume I want to make the array size a compile-time constant:

#define MAXPARM 8 /* for example */

Is there a way to write a clever macro that would expand to v[0],
v[1], ..., v[MAXPARM-1] whatever the value of MAXPARM? (If it helps,
you can assume MAXPARM will never be greater than 100.)

Then I could write:

int v[MAXPARM] = {0};
/* initialize v[0], ..., v[k] where k<MAXPARM */
printf(format, SMART_MACRO(v));


Erm... well, it's clunky, but you could try using the concatenation
macro operator, like this:

#define MAXPARM 8

#define SMART_MACRO_1(a) a[1]
#define SMART_MACRO_2(a) a[1], a[2]
#define SMART_MACRO_3(a) a[1], a[2], a[3]
:
:
#define SMART_MACRO_100(a) a[1], a[2], a[3], ..., a[100]
#define SMART_MACRO(a) SMART_MACRO ## MAXPARM(a)

Note that I may have the details of the ## macro wrong; I'm never quite
sure around # and ## macros. If so, I'm sure some other c.l.c-er will be
more than happy to correct me.

Oh, and if you would like a way to get all those SMART_MACRO_n
definitions into your program without wearing your fingers to the bone,
Richard Heathfield will probably be along any minute now to show you how
to write a C program that writes a C program for you :-)

Richard
Nov 14 '05 #10
Richard Bos wrote:
Grumble wrote:
Bonus question :-)

Assume I want to make the array size a compile-time constant:

#define MAXPARM 8 /* for example */

Is there a way to write a clever macro that would expand to v[0],
v[1], ..., v[MAXPARM-1] whatever the value of MAXPARM? (If it helps,
you can assume MAXPARM will never be greater than 100.)

Then I could write:

int v[MAXPARM] = {0};
/* initialize v[0], ..., v[k] where k<MAXPARM */
printf(format, SMART_MACRO(v));

Erm... well, it's clunky, but you could try using the concatenation
macro operator, like this:

#define MAXPARM 8

#define SMART_MACRO_1(a) a[1]
#define SMART_MACRO_2(a) a[1], a[2]
#define SMART_MACRO_3(a) a[1], a[2], a[3]
:
:
#define SMART_MACRO_100(a) a[1], a[2], a[3], ..., a[100]
#define SMART_MACRO(a) SMART_MACRO ## MAXPARM(a)

Note that I may have the details of the ## macro wrong; I'm never quite
sure around # and ## macros. If so, I'm sure some other c.l.c-er will be
more than happy to correct me.


Couldn't vprintf() come in handy here? (I have never used it.)

Can I build the va_list at run-time?

Then I could call vprintf(format, ap);

--
Regards,

Grumble

Nov 14 '05 #11
In article <news:c0**********@news-rocq.inria.fr>
Grumble <in*****@kma.eu.org> writes:
Couldn't vprintf() come in handy here? (I have never used it.)
Can I build the va_list at run-time?
Then I could call vprintf(format, ap);


This is, in fact, a FAQ -- 15.13 to be precise.

Unfortunately, the less-frequent answer to the F.A.Question
is "no, or at least, not portably."

See 15.5 and 15.12 for why vprintf() exists and when to use it.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Chris | last post by:
(uname -a: Linux srv343.revere.com 2.4.20-30.9 #1 Wed Feb 4 20:44:26 EST 2004 i686 i686 i386 GNU/Linux) I'm pulling my hair out over here... I have a program that forks off a child, and uses...
9
by: | last post by:
void show( char *s, ...) is a function seemd like prinf code -------------- #include <stdio.h> #include <stdarg.h> void show( char *s, ...) { va_list stage;
12
by: baumann | last post by:
hi all, printf("%c",b) doesn't work properly. #include <stdio.h> int a , b; char d, e; char * p; float f; int main(int argc, char* argv) {
29
by: whatluo | last post by:
Hi, c.l.cs I noticed that someone like add (void) before the printf call, like: (void) printf("Timeout\n"); while the others does't. So can someone tell me whether there any gains in adding...
10
by: volunteers | last post by:
Hi, group, I am using a for loop and print such like: for( i=0; i<10; i++) printf("%d", i); so the result look like '1234...', what I want is all the numbers are in one position, mean the...
14
by: Turner, GS \(Geoff\) | last post by:
Out of curiosity, why do programmers insist that the following piece of code printf("%d", 10); is wrong and should be printf("%d\n", 10); It's application specific, isn't it? GST
2
by: Jude | last post by:
here is the source code: #include<stdio.h> int main() { float f; scanf("%d%f",&f); printf("The float is %10.5f\n",f); return 0; } when I input 12345.11111,the output is 12345.11133.
19
by: v4vijayakumar | last post by:
why the following statement dumps the core(Segmentation fault)? printf("%s\n", __FILE__);
19
by: RedDevilDan | last post by:
I am working on a Memory Footprint Reduction project. I came across an idea to disable all printf statements so that less memory is required. In addition, when there is no single printf statement,...
7
by: Avaenuha | last post by:
Hi, It appears my program can't get past a particular printf() statement. Code excerpt: printf("Sales Report\n--------------"); printf("Testing code - pre loop entry"); while(category !=...
1
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...
0
by: veera ravala | last post by:
ServiceNow is a powerful cloud-based platform that offers a wide range of services to help organizations manage their workflows, operations, and IT services more efficiently. At its core, ServiceNow...
0
by: VivesProcSPL | last post by:
Obviously, one of the original purposes of SQL is to make data query processing easy. The language uses many English-like terms and syntax in an effort to make it easy to learn, particularly for...
3
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 3 Jan 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). For other local times, please check World Time Buddy In...
0
by: jianzs | last post by:
Introduction Cloud-native applications are conventionally identified as those designed and nurtured on cloud infrastructure. Such applications, rooted in cloud technologies, skillfully benefit from...
0
by: abbasky | last post by:
### Vandf component communication method one: data sharing ​ Vandf components can achieve data exchange through data sharing, state sharing, events, and other methods. Vandf's data exchange method...
0
by: stefan129 | last post by:
Hey forum members, I'm exploring options for SSL certificates for multiple domains. Has anyone had experience with multi-domain SSL certificates? Any recommendations on reliable providers or specific...
0
Git
by: egorbl4 | last post by:
Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ...
1
by: davi5007 | last post by:
Hi, Basically, I am trying to automate a field named TraceabilityNo into a web page from an access form. I've got the serial held in the variable strSearchString. How can I get this into the...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.