我正在try 创建一个函数类,它可以使用任何数量和任何类型的参数调用--类似于printf,但有一个关键的区别:在将所有参数传递给函数之前,我希望将所有参数强制转换为uint64_t.理想情况下,这应该是隐式的,也就是说,我不必每次都写( uint64_t ) arg1 , ( uint64_t ) arg2 , ( uint64_t ) arg3 , . . ..

我目前的解决方案是基于对前this个问题的回答.

下面是对任何非指针类型执行我想要的操作的基本方法:

// The variadic function.
void _f ( char c , uint64_t arg_count , uint64_t* args );

// Macro to append two extra arguments comprising the variadic argument list to the function.
#define ARGS(...) \
    sizeof ( ( uint64_t[] ){ __VA_ARGS__ } ) / sizeof ( uint64_t ) \
  , ( uint64_t[] ){ __VA_ARGS__ }

// Macro to call the variadic function.
#define f(c,...) \
    _f ( (c) , ARGS ( __VA_ARGS__ ) )

它的使用方法如下:

f ( 'A' , 27 , -30L , '/' );

我还希望能够传递指向函数的指针,但这会触发编译器警告-Wint-conversion,因此我不得不添加一些额外的宏来 suppress 每次调用使用ARGS的函数时的警告,这些宏来自对this的回答:

#define PRAGMA(args) \
    _Pragma ( #args )

#define DISABLE_WARNING(warning)   \
    PRAGMA ( GCC diagnostic push ) \
    PRAGMA ( GCC diagnostic ignored #warning )

#define REENABLE_WARNING() \
    PRAGMA ( GCC diagnostic pop )

// New macro to call the variadic function.
#define f(c,...) \
({ \
    DISABLE_WARNING ( -Wint-conversion ) \
    _f ( (c) , ARGS ( __VA_ARGS__ ) ); \
    REENABLE_WARNING () \
})

现在也可以这样调用该函数:

float f_ = 32.2f;
f ( 'A' , 27 , -30L , '/' , &f_ , &"Hello world" );

但是,由于语法上的限制,在表达式中不能嵌入#pragma,因此函数不能返回值.当然,我可以让函数有一个额外的指针参数,并向它写一个返回值,但理想情况下,我希望函数本身直接返回uint64_t.有办法做到这一点吗?

推荐答案

OP提到了一个限制,即预处理#pragma指令不能嵌入到表达式中.实际上,它can被嵌入到一个表达式中(分布在几行中),但它不能被嵌入到宏定义中.然而,OP没有使用#pragma指令,他们使用的是_Pragma( )运算符,并且can被嵌入到宏定义中.

OP在其f(c,...)宏的定义中使用了GNU GCC"statement expression"扩展(括号中包含的复合语句):

#define f(c,...) \
({ \
    DISABLE_WARNING ( -Wint-conversion ) \
    _f ( (c) , ARGS ( __VA_ARGS__ ) ); \
    REENABLE_WARNING () \
})

如果GNU语句表达式中的最后一个语句或声明是表达式语句,则GNU语句表达式的类型和值就是该表达式语句中的表达式的类型和值,否则GNU语句表达式没有值.

DISABLE_WARNING( -Wint-conversion )REENABLE_WARNING()宏扩展最终扩展为_Pragma( )个操作符的序列,这些操作符在预处理阶段之后被删除,因此不构成任何C表达式,声明或语句的一部分.因此,GNU语句表达式中的最后一个语句或声明是由_f ( (c) , ARGS ( __VA_ARGS__ ) );扩展产生的表达式语句.如果_f声明的返回类型不是void,则GNU语句表达式的类型和值将是调用_f的类型和返回值.

总而言之,OP关于f(c,...)的展开不能从被调用函数_f返回值的说法是错误的.

C++相关问答推荐

Pure Win32 C(++)-除了替换控件的窗口程序之外,还有其他方法可以在输入时禁用按钮吗?

来自stdarg.h的c中的va_args无法正常工作<>

LONG_DOUBLE_T是否存在(标准C:C23)

当我更改编译优化时,相同的C代码以不同的方式运行

为什么该函数不将参数值保存到数据 struct 中?

Make Node函数.S有什么问题吗?

如何在C中打印包含扫描字符和整数的语句?

使用sscanf获取零个或多个长度的字符串

如何在C++中处理按键

防止规范模式在C++中 echo 特殊字符

用C++从外部ELF符号读取值

如何用C语言为CLI应用程序编写按键检测系统?

C语言中的外部关键字

仅从限制指针参数声明推断非混叠

For循环不会迭代所有字符串字符吗?(初学者问题)

使用ld将目标文件链接到C标准库

我在C中运行和调试时得到了不同的输出

C程序向服务器发送TCPRST

如何使用WRITE()以指针地址的十六进制形式写入标准输出

传递给函数的 struct 中的数组