如何使宏返回字符而不是字符串?
我有以下宏(跟进: 在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将理解为一个文字字符串。
我可以看到两个可怕的工作:
-
为每种类型制作mu_assert_equal版本的版本,并使用
_Generic
调用正确的版本。 -
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