我有以下宏(跟随:When writing a macro in C, how do I find the type and printf specifier for an argument?):

#define mu_format_specifier(expression) _Generic((expression), unsigned long: "%lu", int: "%i")

#define mu_assert_equal(actual, expected) do {                                                      \
  if (actual != expected) {                                                                         \
    char *message = malloc(MAX_ERROR_MESSAGE_LENGTH);                                               \
    if (message == NULL) { printf("malloc failed"); exit(1); }                                      \
    snprintf(message, MAX_ERROR_MESSAGE_LENGTH,                                                     \
      "required: %s != %s, reality: %s == " mu_format_specifier(actual),                            \
      #actual, #expected, #actual, actual);                                                         \
    return message;                                                                                 \
  }                                                                                                 \
} while (0)


问题是mu_format_specifier似乎解析为char *,而不是简单地将"%lu"替换为"required: %s != %s, reality: %s == " mu_format_specifier(actual),,我想产生"required: %s != %s, reality: %s == " "%lu",C会将其理解为一个文字字符串。

我可以看到两个可怕的解决方法:


为每种类型制作一个mu_assert_equal版本,并使用_Generic调用正确的版本。
snprintf格式化字符串,但是如果格式化字符串必须为const,我可能会遇到问题。


有更好的选择吗?

(问题是_Generic实际上是对表达式求值,而不是简单地替换源字符-即"%lu"成为它自己的文字字符串,而不仅仅是产生与"required: %s != %s, reality: %s == "统一的源字符。)

最佳答案

我成功了:

#define mu_assert_equal(actual, expected) do {                                            \
  if (actual != expected) {                                                               \
    char *message = malloc(MAX_ERROR_MESSAGE_LENGTH);                                     \
    if (message == NULL) { printf("malloc failed"); exit(1); }                            \
    snprintf(message, MAX_ERROR_MESSAGE_LENGTH, _Generic(                                 \
        (actual),                                                                         \
        unsigned long: "required: %s != %s, reality: %s == %lu",                          \
        int:           "required: %s != %s, reality: %s == %i"                            \
      ),                                                                                  \
      #actual, #expected, #actual, actual);                                               \
    return message;                                                                       \
  }                                                                                       \
} while (0)


解决方案是使整个格式化字符串成为_Generic的输出表达式。

从测试代码:

mu_assert_equal(bytes_parsed, 1);


我得到输出:

required: bytes_parsed != 1, reality: bytes_parsed == 0

09-04 02:51
查看更多