我如何创建一个带有可变数量参数的宏,并使用std :: cout打印出来?很抱歉,如果这是一个菜鸟问题,在搜索答案后找不到任何澄清可变参数的宏.
概念示例:
#include <iostream>
#define LOG(...) std::cout << ... << ... << std::endl
int main() {
LOG("example","output","filler","text");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
exampleoutputfillertext
Run Code Online (Sandbox Code Playgroud) 我一直在考虑如何在C宏中验证类型,到目前为止,我提出的最佳方法是:
#define ASSERT_PTYPE(TYPE, VALUE) (0 && (*(int (*)(TYPE*))0)(VALUE))
Run Code Online (Sandbox Code Playgroud)
这显然需要一个类型名称和指向该类型的指针.也可以制作类似的ASSERT_TYPE宏.这对GCC来说似乎很有效.它甚至在类型不匹配的情况下提供了非常有用的错误消息.问题是我不能完全确定这是有效的C还是最好的方法.
据我所知,标准说您可以转换函数指针,但调用转换函数指针的结果是未定义的.在这种情况下,不可能在运行时调用该函数.这是否足够好或标准意味着你甚至不能编写无法调用的代码来调用强制转换函数?
让我们说我希望C macro适用于任何类型.我正在使用GCC编译器(> = 4.6)并且可以使用GNU99宏.
//code...
any_type_t *retVal = function_that_runs_very_long_time(a, b, &&c, **d, &e, *f);
//other code...
Run Code Online (Sandbox Code Playgroud)
用于TIMER的宏的用法可以看起来像这样
//code...
any_type_t *retVal =
TIMER(
function_that_runs_very_long_time(a, b, &&c, **d, &e, *f),
"TIMING FOR VALUE <%d, %d>", a, b
);
//other code...
Run Code Online (Sandbox Code Playgroud)
因此TIMER必须返回给定函数的值和其运行的打印持续时间.具有void返回类型的函数存在问题.
我显然可以有两个宏,如TIMER_TYPE和TIMER_VOID,但我想使用单一的时间函数与任何返回值.
谢谢你的建议.
编辑此TIMER宏的示例
#define TIMER(expr, fmt_msg, ...) \
({ \
struct timeval before, after; \
uint64_t time_span; \
int time_span_sec, time_span_usec; \
gettimeofday(&before, NULL); \
typeof(expr) _timer_expr__ = (expr); \ // <- static if?
gettimeofday(&after, NULL); \
time_span = …Run Code Online (Sandbox Code Playgroud) 在我工作的项目中,我们有一些实用程序宏,它们多次引用它们的参数.
让我们用一个简单的例子:
#define ABS(a) ( (a) < 0 ? (-(a)) : (a) )
Run Code Online (Sandbox Code Playgroud)
现在这是一个很大的代码库,当我们检查代码时,我偶尔会发现一个函数调用被传递给宏.这不是错误,但它意味着多次进行函数调用,这通常是我不想要的.
在这种情况下,我们可以将其替换fabsf,fabs,abs用于float/ double/ int至少,但是让我们假设存在并不总是一个好的内置的更换和宏将留下一个宏.
例:
f = ABS(dot_v3v3(vel, sp));
/* expands into */
f = ( ( dot_v3v3(vel, sp) ) < 0 ? (-( dot_v3v3(vel, sp) )) : ( dot_v3v3(vel, sp) ) );
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:
是否可以检测宏内使用的函数调用(警告或错误)?
以下是我已经检查过的一些事情......
这将导致函数调用不编译,但缺点是像'1'这样的常量也会出现错误以及像(b-c)这样的表达式.
#define ABS(a) ((void)((&a) == (&a)), ( (a) < 0 ? (-(a)) : (a) ))
Run Code Online (Sandbox Code Playgroud)
注意:我发现这已经非常方便地指出了一些不好的宏用法,但由于它有误报,所以它不能留下来.
我最近开始使用谷歌测试来帮助我测试程序.它运作良好,但现在我的测试用例正在增长......
#include <gtest/gtest.h>
TEST(MyTest, FirstTest) {
// stuff
};
TEST(MyTest, SecondTest) {
// stuff
};
TEST(MyTest, ThirdTest) {
// stuff
};
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
};
Run Code Online (Sandbox Code Playgroud)
我想为我的所有测试创建一个很好的自动生成的文档,这些文档将与我的程序文档分开.出于这个目的,我通常使用doxygen,但谷歌测试使用宏,目前还不清楚doxygen如何处理.更准确地说,我们有
#define TEST(test_case_name, test_name)\
GTEST_TEST_(test_case_name, test_name, \
::testing::Test, ::testing::internal::GetTestTypeId())
Run Code Online (Sandbox Code Playgroud)
我试过了
/**
* @def TEST(MyTest, FirstTest)
* @brief My first test
*/
TEST(MyTest, FirstTest) {
// stuff
};
Run Code Online (Sandbox Code Playgroud)
但它不会在doxygen上产生任何输出......
作为练习,我想写一个宏,它告诉我是否签署了整数变量.这就是我到目前为止所得到的结果,如果我在使用gcc -fsigned-char或-funsigned-char的char变量上尝试这个结果,我会得到结果.
#define ISVARSIGNED(V) (V = -1, (V < 0) ? 1 : 0)
Run Code Online (Sandbox Code Playgroud)
这是便携式吗?有没有办法在不破坏变量值的情况下执行此操作?
#include < iostream >
#define MY_CHK_DEF(flag) \
#ifdef (flag) \
std::cout<<#flag<<std::endl; \
#else \
std::cout<<#flag<<" ,flag not define"<<std::endl; \
#endif
int main()
{
MY_CHK_DEF(FLAG_1);
MY_CHK_DEF(FLAG_2);
MY_CHK_DEF(FLAG_3);
...
}
Run Code Online (Sandbox Code Playgroud)
编者报告:
main.cpp:3:24:错误:'#'后面没有宏参数
有任何想法吗?
谢谢
我有两个功能:
void foo0(int bar);
void foo1(int bar);
Run Code Online (Sandbox Code Playgroud)
我不能创建一个宏QUX,它将根据另一个宏扩展到这些函数名称BAZ.我尝试了以下方法:
#define BAZ 0
#define QUX(x) foo##BAZ(x)
Run Code Online (Sandbox Code Playgroud)
但是由于生成的函数是无效的,所以它不起作用fooBAZ().我怎样才能让它生成foo0()?
我试图在C中进行面向对象,并希望为符号设置一个语法糖宏
object->vtable->method(object, arg1, arg2)
Run Code Online (Sandbox Code Playgroud)
成
send(object, method, arg1, arg2)
Run Code Online (Sandbox Code Playgroud)
不幸的是,当一个方法没有参数时,会出现尾随的逗号问题
send(object, method)
Run Code Online (Sandbox Code Playgroud)
给
object->vtable->method(object, )
Run Code Online (Sandbox Code Playgroud)
是否有任何便携式(无##__VA_ARGS__或Visual Studio)方式?
我想出了一个,但我需要交换对象和方法
#define FIRST_ARG_(N, ...) N
#define FIRST_ARG(args) FIRST_ARG_(args)
#define send(msg, ...) \
FIRST_ARG(__VA_ARGS__)->vtable->msg(__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)
许可证
send(method, object)
send(method, object, arg1, arg2)
Run Code Online (Sandbox Code Playgroud)
编辑
在下面两个很好的答案的帮助下,我将使用这些宏来完成.它最多可以处理16个参数,但可以轻松扩展
#define SEND_NO_ARG(obj, msg) obj->vtable->msg(obj)
#define SEND_ARG(obj, msg, ...) obj->vtable->msg(obj, __VA_ARGS__)
#define GET_18TH_ARG(arg1, arg2, arg3, arg4, arg5, \
arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, \
arg16, arg17, arg18, ...) arg18
#define SEND_MACRO_CHOOSER(...) \
GET_18TH_ARG(__VA_ARGS__, …Run Code Online (Sandbox Code Playgroud) 我有几个数据结构,每个数据结构有4个字节的字段.
由于int我的平台上4个字节等于1 ,我想在case标签中使用它们:
switch (* ((int*) &structure->id)) {
case (* ((int*) "sqrt")): printf("its a sqrt!"); break;
case (* ((int*) "log2")): printf("its a log2!"); break;
case (((int) 'A')<<8 + (int) 'B'): printf("works somehow, but unreadable"); break;
default: printf("unknown id");
}
Run Code Online (Sandbox Code Playgroud)
这会导致编译错误,告诉我case表达式不会减少到int.
我如何使用有限大小的char数组,并将它们转换为数值类型以用于switch/ case?