如何使用自适应类型的printf()函数?

时间:2013-02-14 09:54:34

标签: c printf

让我解释一下情况: 我有一个C结构如下:

typedef struct {
  int *val;
  char *name;
} tStruct;

此结构可能填充如下: - 如果“val”值不可用,则val可以为null,否则val是整数值(可以是负数) - 如果名称不可用,则name可以是空字符串;如果名称可用,则name可以是填充字符串(此处不是空指针)。

我希望写一个日志行如下:

  • 如果val无效,则名称有效(等于WOOT):
  

LOG val =#name = WOOT

  • 如果val无效,则名称无效:
  

LOG val =#name =#

  • 如果val有效,则名称无效:
  

LOG val = 123456 name =#

  • 如果val有效,则name有效(等于WOOT):
  

LOG val = 123456 name = WOOT

这意味着我需要使用printf(“val =%s name =%s”,...)或printf(“val =%d name =%s”,...),具体取决于id值(这样我可以输出#或整数)。当val无效时输出伪整数值是不合适的,因为任何有符号或无符号值都是可能的。

有什么想法吗?我希望我可以避免使用以下类型的构造,因为我的struct实际上会包含很多字段,使得“if”组合太多了:

if ( (struct.val == NULL ) && ( struct.name ) ) then printf ("val=# name=%");
else if ((struct.val == NULL ) && ( ! struct.name ) ) then printf ("val=# name=#");
else if ...

谢谢

5 个答案:

答案 0 :(得分:3)

创建一个返回该类型的字符串表示形式的函数,然后在printf

中使用它
printf("%s", tStruct_to_string(contents));

请注意,除非你的转换函数有一些静态缓冲区,否则很难以的方式使用它。

编辑:这里使用单个静态缓冲区是错误的,因为它不适用于多个参数。正如@pmg所说,接受缓冲区更好,但风险缓冲区溢出,所以也许你可以传递长度作为参数,但现在优雅的解决方案并不像它那样优雅。因此,您的函数可以返回malloced char *,但之后您可以释放它,并且动态分配可能很慢。 Ufff ...在C中管理字符串是相当痛苦的。

我现在能想到的最好的方法(但是它存在重入问题)是拥有静态字符串数组并在每次调用时循环使用它们。

char* tStruct_to_string(tStruct st)
{
    /* 
     * here assuming no one will call printf 
     * with more than 32 arguments of this type,
     * and assuming length of string 100.
     */ 
    static char strings[32][100];
    static int next = 0;
    int current = next;
    // here you write to strings[current]
    // use s(n)printf for writing to string
    next = (next+1)%32;
    return strings[current];
}

此外,其他答案提供了如何避免重复条件的极好建议。

答案 1 :(得分:2)

printf("LOG val=");
if (struct.val) printf("%d", *struct.val); else printf("#");
printf(" name=");
if (*struct.name) printf("%s", struct.name); else printf("#");
printf("\n");

答案 2 :(得分:1)

对于val成员,您必须使用if语句,因为输出是字符串或数字,但对于name,您可以使用ternary expression }:

if (str.val)
    printf("val=%d name=%s", *str.val, *str.name == '\0' ? "#" : str.name);
else
    printf("val=# name=%s", *str.name == '\0' ? "#" : str.name);

答案 3 :(得分:1)

如果你的结构有很多这样的对,那么显而易见的是将一个对的打印分解为一个函数,然后为实际结构中的每一对调用它。

void print_pair(const int *value, const char *name)
{
    if(value == NULL && name == NULL)
      printf("val=# name=#");
    else if(value == NULL && name != NULL)
      printf("val=# name=%s", name);
    else if(value != NULL && name == NULL)
      printf("val=%d name=#", *value);
    else
      printf("val=%d name=%s", *value, name);
}

您可以使用#也可以表示为字符串的事实来缩短上述内容。

你可以通过分解出以两种方式将整数转换为字符串的想法来缩短它,但这可能会过度:

void print_pair(const int *value, const char *name)
{
    char vbuf[32];

    if(value == NULL)
      strcpy(vbuf, "#");
    else
      snprintf(vbuf, sizeof vbuf, "%d", *value);

    printf("val=%s name=%s", vbuf, name != NULL ? name : "#");
}

答案 4 :(得分:1)

为什么要通过所有这些努力将所有内容压缩到一个printf调用中?只需打两次电话。

if (s.val)
    printf("val=%d ", *s.val);
else
    printf("val=# ");
printf("s.name=%s", s.name ? *s.name : "#");