如何使宏返回字符而不是字符串?

我有以下宏(跟进: 在C中编写宏时,如何找到参数的类型和printf说明符? ):

#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将理解为一个文字字符串。

我可以看到两个可怕的工作:

  1. 为每种类型制作mu_assert_equal版本的版本,并使用_Generic调用正确的版本。

  2. snprintf格式化字符串,但如果格式化字符串必须是const ,我可能会遇到问题。

还有更好的选择吗?

(问题是_Generic实际上是在计算表达式,而不是简单地替换源字符 – 即"%lu"成为它自己的文字字符串,而不仅仅是生成与"required: %s != %s, reality: %s == "统一的源字符"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