0

我的 TLV 结构可以保存字符串或整数。我正在尝试创建一个可以同时处理它们的宏。

下面的示例按预期运行,但它编译时带有来自 MACRO 扩展的警告。我知道预编译器无法知道我将在运行时分配什么类型的值,这就是我认为它会发出警告的原因。

如何修复这个小代码片段,使其不产生编译警告?

FWIW,我可以通过不使用 MACRO 来解决这个问题,但如果可能的话,我更愿意使用它。

$ gcc -o simple{,.c} && ./simple
simple.c: In function ‘main’:
simple.c:25:21: warning: assignment makes pointer from integer without a cast [enabled by default]
       tlv.value_str = (val); \
                     ^
simple.c:38:3: note: in expansion of macro ‘TLV2STR_MACRO’
   TLV2STR_MACRO(string, TYPE_INT, 11);
   ^
simple.c:28:21: warning: assignment makes integer from pointer without a cast [enabled by default]
       tlv.value_int = (val); \
                     ^
simple.c:41:3: note: in expansion of macro ‘TLV2STR_MACRO’
   TLV2STR_MACRO(string, TYPE_STRING, "ELEVEN");
   ^
-----------------------------
INT   : 11
STRING: ELEVEN
-----------------------------
#include <stdio.h>

typedef struct _tlv_s {
  int type;
  size_t length;
  union _value {
    int value_int;
    char *value_str;
  } value_u;
} tlv_t;

#define value_int value_u.value_int
#define value_str value_u.value_str

#define TYPE_STRING 0
#define TYPE_INT 1

#define TLV2STR_MACRO(s, t, val) { \
    tlv_t tlv; \
    tlv.type = (t); \
    if (t == TYPE_STRING) { \
      tlv.value_str = (val); \
      sprintf(s, "STRING: %s", tlv.value_str); \
    } else { \
      tlv.value_int = (val); \
      sprintf(s, "INT   : %d", tlv.value_int); \
    } \
}

int main(int argc, char *argv[])
{
  char string[128];

  printf("-----------------------------\n");
  TLV2STR_MACRO(string, TYPE_INT, 11);
  printf("%s\n", string);

  TLV2STR_MACRO(string, TYPE_STRING, "ELEVEN");
  printf("%s\n", string);
  printf("-----------------------------\n");

}
4

2 回答 2

0

如何修复这个小代码片段,使其不产生编译警告?

您可以添加显式强制转换。

tlv.value_str = (char*)(val); \
tlv.value_int = (int)(val); \

对于您的 FWIW,这样的宏不会扩大规模,虽然为具有两种类型和一个用例的玩具示例编写速度很快,但当更多的时候它会变得痛苦和不可读。使用带调度功能的虚拟表,保持代码可读,不喜欢使用宏。我建议删除令人困惑的定义#define value_int value_u.value_int并将您的符号保留在一个命名空间内tlv_*。不要以不可读的大开关结束,您的代码似乎正在这样做。更喜欢使用snprintf而不是sprintf.

于 2021-07-05T11:42:52.763 回答
0

我相信(很高兴被证明不是这样)不可能按照我的意图传递值,将它们任意转换为字符串或整数。

相反,传递指向值的指针并转换指针是执行此操作的正确方法。(顺便说一句,如果这真的是一个 TLV 实现,它可以处理任何类型的结构,但这只是一个小应用程序,用于演示传递值的问题)。

请注意,我修改了宏以接受指向该值的指针。

#include <stdio.h>

typedef struct _tlv_s {
  int type;
  size_t length;
  union _value {
    int value_int;
    char *value_str;
  } value_u;
} tlv_t;

#define value_int value_u.value_int
#define value_str value_u.value_str

#define TYPE_STRING 0
#define TYPE_INT 1

#define TLV2STR_MACRO(s, t, valp) { \
    tlv_t tlv; \
    tlv.type = (t); \
    if (t == TYPE_STRING) { \
      tlv.value_str = (char *)(valp); \
      sprintf(s, "STRING: %s", tlv.value_str); \
    } else { \
      tlv.value_int = *(int *)(valp); \
      sprintf(s, "INT   : %d", tlv.value_int); \
    } \
}

int main(int argc, char *argv[])
{
  char string[128];
  int val_int = 11;

  printf("-----------------------------\n");
  TLV2STR_MACRO(string, TYPE_INT, &val_int);
  printf("%s\n", string);

  TLV2STR_MACRO(string, TYPE_STRING, "ELEVEN");
  printf("%s\n", string);
  printf("-----------------------------\n");

}

以及编译和运行的输出......

$ gcc -o simple{,.c} && ./simple asdf 
-----------------------------
INT   : 11
STRING: ELEVEN
-----------------------------
于 2021-07-05T21:31:49.713 回答