printf与运行时格式字符串 [英] printf with run-time format strings

查看:66
本文介绍了printf与运行时格式字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好,


我有以下结构:


struct foo {

char * format; / *格式字符串与printf()* /

int nparm一起使用; / *格式字符串中%d个说明符的数量* /

/ * 0< = nparm< = 4 * /

};


例如


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


我可以写:


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


假设我有一个正确初始化的struct foo数组:


struct foo array [100]; ... / *初始化数组* /


我想打印每个结构foo。我是否必须针对nparm的每个可能值制作一个特殊情况

?如:


for(i = 0; i< 100; ++ i)

{

switch(array [i] .parm)

{

案例0:

printf(array [i] .format);休息;

案例1:

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

...

案例4:

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

}

}


难道没有更好的办法吗?如果我认为就堆栈而言(我知道

是clc中的一个罪恶)我应该能够将很多参数推到堆栈上,推动参数个数或NULL(我是

不确定printf如何工作)然后跳转到printf代码。


我''从未使用过变量函数。在这种情况下,它们能证明有用吗?


问候,


Grumble

解决方案

Grumble< in ***** @ kma.eu.org>写道:

我有以下结构:

struct foo {
char * format; / *格式字符串与printf()* /
int nparm一起使用; / *格式字符串中的%d个说明符的数量* /
/ * 0< = nparm< = 4 * /
};



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

我可以写:

printf(吧。 format,rand(),rand(),rand());


是的。请注意,你不知道调用rand()的顺序是什么。

使用rand(),这显然不是很重要,但是如果你

替换一个从堆栈中弹出一个值的函数代替,你可能会因为一个惊喜而接受
...

假设我有一个正确初始化的struct foo数组:

struct foo array [100]; ... / *初始化数组* /

我想打印每个struct foo。我是否必须针对nparm的每个可能值创建一个特殊情况?如:(i = 0; i< 100; ++ i)
{
switch(array [i] .parm)
{<案例0:
printf(array [i] .format);打破;
案例1:
printf(array [i] .format,rand());打破;
......
案例4:
printf(array [i] .format,rand(),rand(),rand(),rand());休息;
}
}


你真的需要使用printf()。如果您提前知道

参数的最大数量是有限的,这不是一个很糟糕的

方法。

Isn'有更好的方法吗?如果我认为在堆栈方面(我知道
在c.l.c中是一个罪恶)


你什么都不知道。为什么使用堆栈是罪?您在ISO C中无法做到的
是使用任何类型的系统,硬件或程序堆栈,

但没有什么可以阻止您创建自己的堆栈ADT。

我应该能够将很多参数推到堆栈上,推送参数个数或NULL(我不确定) printf如何工作)然后跳转到printf代码。


啊,好吧,_that_是不可能的。 printf()不知道如何使用你的

堆栈,你不能干扰它的堆栈。我甚至不会尝试

你也可以;风险太高了。

我从未使用过变量函数。


(是的,你有; printf()是一个。)

它们在这种情况下是否有用?




不是我能看到的。 < STDARG.H>用于编写传递给它们的可变数量参数的函数,而不是用于传递变量

其他函数的参数数量。如果

可能会有用,但唉,这不是。


Richard


"叽" <在***** @ kma.eu.org>在留言中写道

news:c0 ********** @ news-rocq.inria.fr ...

你好,
<我有以下结构:

struct foo {
char * format; / *格式字符串与printf()* /
int nparm一起使用; / *格式字符串中的%d个说明符的数量* /
/ * 0< = nparm< = 4 * /
};



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

我可以写:

printf(吧。 format,rand(),rand(),rand());

假设我有一个正确初始化的struct foo数组:

struct foo array [100]; ... / *初始化数组* /

我想打印每个struct foo。我是否必须针对nparm的每个可能值创建一个特殊情况?如:(i = 0; i< 100; ++ i)
{
switch(array [i] .parm)
{<案例0:
printf(array [i] .format);打破;
案例1:
printf(array [i] .format,rand());打破;
......
案例4:
printf(array [i] .format,rand(),rand(),rand(),rand());休息;
}
}

有没有更好的方法?如果我认为在堆栈方面(我知道
是clc中的一个罪恶)我应该能够将很多参数推到堆栈上,推送参数的数量或NULL(我不确定printf是如何工作的,然后跳转到printf代码。

我从未使用过variadic函数。在这种情况下它们能证明有用吗?

问候,

Grumble



就像你说的那样,你可以编写自己的函数其行为类似于printf()

并以链接列表的形式获取其参数列表,或者在运行时可以提供的任何其他含义




如果您仍想使用printf(),并且在Intel x86上,您可以在for循环中将自己的

参数推送到堆栈。

通过观察普通printf()调用的程序集输出,你可以理解如何在运行时传递额外的参数,好像它们是由编译器添加的./ $
。 br />

-

Elias





Grumble写道:

你好,

我有以下结构:

struct foo {
char * format; / *格式字符串与printf()* /
int nparm一起使用; / *格式字符串中的%d个说明符的数量* /
/ * 0< = nparm< = 4 * /
};



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

我可以写:

printf(吧。 format,rand(),rand(),rand());

假设我有一个正确初始化的struct foo数组:

struct foo array [100]; ... / *初始化数组* /

我想打印每个struct foo。我是否必须针对nparm的每个可能值创建一个特殊情况?如:(i = 0; i< 100; ++ i)
{
switch(array [i] .parm)
{<案例0:
printf(array [i] .format);打破;
案例1:
printf(array [i] .format,rand());打破;
......
案例4:
printf(array [i] .format,rand(),rand(),rand(),rand());休息;
}
}

有没有更好的方法?如果我认为在堆栈方面(我知道
是clc中的一个罪恶)我应该能够将很多参数推到堆栈上,推送参数的数量或NULL(我不确定printf是如何工作的,然后跳转到printf代码。




我不确定它是不是更好的方法但是你可以在最后的printf参数中创建一个

的宏。如果有更多的参数,那么

是说明符,剩下的参数将被评估,否则

被忽略。


#define ARGS rand(),rand(),rand(),rand()/ *最多4个args * /


然后你printf看起来会这样:

printf(array.format,ARGS);


示例:


#include< stdio.h>

#include< string.h>

#include< stdlib.h>


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

struct foo {

char * format; / *格式字符串与printf()* /

unsigned nparm一起使用; / *格式字符串中%d个说明符的数量* /

/ * 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);

免费(myfoo.format);

返回0;

}


struct foo addFoo(const char * format)

{/ * TODO添加代码以确保%d * /

struct foo tmp = {NULL};

const char * cs;

unsigned cnt;

size_t len = strlen(格式);


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");

}

返回tmp;

}


-

Al Bowers

美国佛罗里达州坦帕市

mailto: xa ****** @ myrapidsys.com (删除x以发送电子邮件)
http: //www.geocities.com/abowers822/


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

解决方案

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


"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




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/


这篇关于printf与运行时格式字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆