2

Let me explain the situation : I have a C struct as follows :

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

This structure might be populated as follows : - val can be null if the "val" value is not available, otherwise val is an integer value (can be negative) - name can be an empty string if name is not available, or a filled string (not null pointer here) if a name is available.

I wish to write a log line as follows :

  • if val is invalid, name is valid (equals WOOT):

LOG val=# name=WOOT

  • if val is invalid, name is invalid :

LOG val=# name=#

  • if val is valid, name is invalid:

LOG val=123456 name=#

  • if val is valid, name is valid (equals WOOT):

LOG val=123456 name=WOOT

This means I'd need to use either printf("val=%s name=%s",...) or printf("val=%d name=%s",...) depending on the id value (so that I can either output a # or the integer). Outputing a fake integer value when val is invalid is not suitable since any signed or unsigned value is possible.

Any idea ? I wish I could avoid the following kind of construct because my struct will actually contain many fields, making too many the "if" combinations :

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

Thank you

4

5 回答 5

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];
}

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

于 2013-02-14T10:00:23.223 回答
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");
于 2013-02-14T09:58:22.967 回答
1

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

if (s.val)
    printf("val=%d ", *s.val);
else
    printf("val=# ");
printf("s.name=%s", s.name ? *s.name : "#");
于 2013-02-14T10:25:11.190 回答
1

对于val成员,您必须使用if语句,因为输出是字符串或数字,但对于name您可以使用三元表达式

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);
于 2013-02-14T10:01:14.080 回答
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 : "#");
}
于 2013-02-14T10:01:22.700 回答