相关疑难解决方法(0)

在参数数量上重载宏

我有两个宏,FOO2并且FOO3:

#define FOO2(x,y) ...
#define FOO3(x,y,z) ...
Run Code Online (Sandbox Code Playgroud)

我想定义一个新的宏FOO如下:

#define FOO(x,y) FOO2(x,y)
#define FOO(x,y,z) FOO3(x,y,z)
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为宏不会在参数数量上超载.

无需修改FOO2FOO3,是有一些方法来定义一个宏FOO(使用__VA_ARGS__或以其他方式),以获得分派的相同的效果FOO(x,y)FOO2,并FOO(x,y,z)FOO3

c macros c-preprocessor

168
推荐指数
6
解决办法
5万
查看次数

究竟哪种双串联技巧有效?

至少有一些C预处理器允许你将宏的值(而不是它的名称)通过一个类似函数的宏传递给另一个将它串行化的宏来进行字符串化:

#define STR1(x) #x
#define STR2(x) STR1(x)
#define THE_ANSWER 42
#define THE_ANSWER_STR STR2(THE_ANSWER) /* "42" */
Run Code Online (Sandbox Code Playgroud)

这里的用例示例.

这确实有效,至少在GCC和Clang(两者都有-std=c99),但我不确定它是如何工作的C标准术语.

这种行为是否由C99保证?
如果是这样,C99如何保证呢?
如果不是,那么从C定义到GCC定义的行为在什么时候?

c stringification c-preprocessor

81
推荐指数
2
解决办法
2万
查看次数

MSVC不会正确扩展__VA_ARGS__

考虑以下代码:

#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) F(__VA_ARGS__)
F(1, 2, 3)
G(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)

X = 1 and VA_ARGS = 2, 3两个宏的预期输出,这就是我用GCC得到的,但是,MSVC将其扩展为:

X = 1 and VA_ARGS = 2, 3
X = 1, 2, 3 and VA_ARGS =
Run Code Online (Sandbox Code Playgroud)

也就是说,__VA_ARGS__将其扩展为单个参数,而不是分解为多个参数.

有什么方法吗?

visual-c++ c-preprocessor variadic-macros

48
推荐指数
2
解决办法
1万
查看次数

循环通过宏Varargs值

如果我定义一些宏:

#define foo(args...) ({/*do something*/})
Run Code Online (Sandbox Code Playgroud)

有没有办法实际循环args而不是传递给另一个函数?就像是

#define foo(args...) \
        { \
           for (int i = 0; i < sizeof(args); ++i) { \
             /*do something with args[i]*/ \
           } \
         }
Run Code Online (Sandbox Code Playgroud)

c macros variadic-functions

18
推荐指数
1
解决办法
9420
查看次数

Variadic UNUSED函数/宏

抑制C编译器有关未使用变量的警告的一种众所周知的可移植方法是(参见C代码中未使用的参数警告):

#define UNUSED(x) (void)(x)
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种方法来概括它以获取多个输入(不同类型):

void foo(int a, long b, void* c){

   /* Want this: */
   ALL_UNUSED(a, b, c);

   /* instead of: */
   UNUSED(a);
   UNUSED(b);
   UNUSED(c);
}
Run Code Online (Sandbox Code Playgroud)

似乎可以解决的一种方法是使用可变参数函数

static inline void ALL_UNUSED(int dummy, ...) {}
Run Code Online (Sandbox Code Playgroud)

但是,我怀疑这种解决方案在专家眼中是令人反感的.

是否有符合标准且可移植(即不使用__attribute__((unused)))的方式来制作可变参数UNUSED()函数/宏?非常感谢!

编辑

在C99或C预处理器的上下文中似乎没有一种干净的方式来执行我的要求.这就是人生.

在下面的回答中,@ Dabo展示了一种非常有趣的方式来做我要求使用的一系列宏.这是整洁和翔实的(至少对我来说),所以我接受这个答案.也就是说,我不会将它部署在一个大型项目中,因为它的篇幅足以超过它带来的好处(在我看来).但人们会在这里得出不同的结论.

如下所述,使用空可变参数函数的方法也不完美.虽然它是一个非常优雅的单行,但它会引发有关单元化变量的警告(如果是的话).此外,你必须相信你的编译器完全优化它,我原则上反对,但我尝试过的所有编译器实际上都是这样做的.

一个相关的情况是在早期高级接口设计阶段之后存根功能.那么你未使用的变量都将是函数参数并按定义初始化,以下方法可以正常工作

static inline void UNUSED(int dummy, ...) {}

void foo(int a, long b, void* c){
    UNUSED(a, b, b); /* No warnings */
}
Run Code Online (Sandbox Code Playgroud)

c macros c-preprocessor

11
推荐指数
1
解决办法
4008
查看次数

是否可以使用预处理器(宏)将C字符串文字转换为大写?

忽略有时候有更好的非宏方式来做这件事(遗憾的是我有充分的理由),我需要使用宏编写一大堆通用代码.本质上是一个宏库,它将为某些预先指定的类型生成大量函数.

为了避免破坏大量预先存在的单元测试,库必须做的一件事是,对于每种类型,在所有大写字母中生成该类型的名称以进行打印.例如,类型"标志"必须打印为"标记".

我可以手动写出每种类型的常量,例如

#define flag_ALLCAPSNAME标志

但这并不理想.我希望能够以编程方式执行此操作.

目前,我一起攻击了这个:

char capname_buf[BUFSIZ];
#define __MACRO_TO_UPPERCASE(arg) strcpy(capname_buf, arg); \
 for(char *c=capname_buf;*c;c++)*c = (*c >= 'a' && *c <= 'z')? *c - 'a' + 'A': *c;
__MACRO_TO_UPPERCASE(#flag)
Run Code Online (Sandbox Code Playgroud)

我在某种程度上做了我想做的事情(即在这段代码之后,capname_buf将"FLAG"作为其内容),但我更喜欢一种允许我使用宏来定义字符串文字的解决方案,避免了对此的需要愚蠢的缓冲.

我看不出怎么做,但也许我错过了一些明显的东西?

我有一个可变的foreach循环宏写(像这一个),但我不能改变#flag生成的字符串文字的内容,并且无论如何,我的循环宏需要一个字符指针列表来迭代(即它迭代列表,而不是索引等.

思考?

c macros c-preprocessor

10
推荐指数
1
解决办法
9493
查看次数

C++预处理器宏循环__VA_ARGS__ 1 vs 2+参数

我正在使用此帖子中的宏循环遍历我的参数.一切都很棒!但是,有没有办法这两个结合起来CCB_CREATE,并CCB_CREATE_MORE

我需要提取第一个参数object_type来编写其他代码.附加的object_types将使用FOR_EACH循环插入到地图中.

当我在使用时只有一个参数时,编译器会抱怨CCB_CREATE_MORE(Type1).为了解决这个问题,我制作了另一个宏来处理它CCB_CREATE(Type1).希望找到一个聪明的解决方案,将这两者结合成一个优雅的宏.有任何想法吗?

#define INSERT_LOADER_MAP(object_type) loader_map.insert(make_pair(#object_type, object_type##Loader::loader()))


#define CCB_CREATE_MORE(object_type,...) \
static CCNode * create##object_type##Node() { \
    std::map<std::string, CCNodeLoader*> loader_map; \
    std::string classname = #object_type; \
    FOR_EACH(INSERT_LOADER_MAP,object_type,__VA_ARGS__); \
    return loadCCBFile((classname + ".ccbi").c_str(), loader_map); \
}


#define CCB_CREATE(object_type) \
static CCNode * create##object_type##Node() { \
    std::map<std::string, CCNodeLoader*> loader_map; \
    std::string classname = #object_type; \
    INSERT_LOADER_MAP(object_type); \
    return loadCCBFile((classname + ".ccbi").c_str(), loader_map); \
}
Run Code Online (Sandbox Code Playgroud)

c++ macros

8
推荐指数
1
解决办法
3986
查看次数

如何使用SWIG包装std :: function对象?

我看过很多类似的问题,但还没有找到解决我特定问题的方法.我试图SWIGify一些使用std :: function的C++ 11代码,所以我可以在我的Java应用程序中使用它.

我遇到过像这样的共享指针:

virtual std::shared_ptr<some::ns::TheThing> getTheThing(unsigned short thingID);
Run Code Online (Sandbox Code Playgroud)

并使用shared_ptr指令成功处理它们,如下所示:

%shared_ptr(some::ns::TheThing);
Run Code Online (Sandbox Code Playgroud)

我遇到过这样的共享指针向量:

virtual std::vector<std::shared_ptr<some::ns::TheThing>> getAllTheThings() const = 0;
Run Code Online (Sandbox Code Playgroud)

并使用如下模板成功处理它们:

%template(ThingVector) std::vector<std::shared_ptr<some::ns::TheThing>>;
Run Code Online (Sandbox Code Playgroud)

现在我有一个像这样的方法:

 void registerThingCallback(std::function<void(std::shared_ptr<some::ns::TheThing>) > func);
Run Code Online (Sandbox Code Playgroud)

我无法让SWIG正确包装它.我已经尝试使用%回调,导演,%模板和%内联功能代码,因为我已经看到所有这些事情的例子,但是还没有能够得到任何似乎接近工作的东西.如果有帮助(清理和减少),这里有一个关于函数调用的更多上下文:

thing_callback.h

#include <functional>

namespace some {
  namespace ns {

    /**
     * Hold some callbacks.
     */
    class ThingCallbacks {
    public:

        /**
         * Registers a callback 
         * @param func The callback function
         */
        void registerThingCallback(std::function<void(std::shared_ptr<some::ns::TheThing>) > func);

    };

  }
}
Run Code Online (Sandbox Code Playgroud)

更新

根据Flexo下面的答案,我更接近解决方案.我能够让下面的例子完全像宣传的那样工作.我尝试将它合并到我的实际代码中,但遇到了问题.为了扩展我之前的简化示例,这里是我对TheThing的定义:

test_thing.h

#ifndef THE_THING_H
#define THE_THING_H

#include <string>

namespace some {
  namespace ns …
Run Code Online (Sandbox Code Playgroud)

c++ java swig c++11 std-function

8
推荐指数
1
解决办法
2229
查看次数

当路径中存在同名文件时,跨平台方式包含系统头文件?

我试图让Bloomberg的BDE库在Visual Studio 2015中编译.因为它们重新实现了编译器通常提供的标准库,所以有一些头文件的名称与标准库名称完全匹配,例如stddef.h.它们可选地允许您关闭标准库的覆盖,为此,它们重新实现的文件可选地只包括原始编译器提供的版本,例如stddef.h.他们这样做包括通过宏,如下所示:

#   if defined(BSLS_COMPILERFEATURES_SUPPORT_INCLUDE_NEXT)
#     include_next <stddef.h>
#   else
#     include BSL_NATIVE_C_LIB_HEADER(stddef.h)
#   endif
Run Code Online (Sandbox Code Playgroud)

资源

在哪里BSL_NATIVE_C_LIB_HEADER扩展到这样的东西:

#if defined(BSLS_PLATFORM_CMP_SUN) // Sun Compiler
#   define BSL_NATIVE_C_LIB_HEADER(filename) <../include/filename>

#elif defined(BSLS_PLATFORM_CMP_CLANG) || defined(BSLS_PLATFORM_CMP_GNU)
  // Clang and GCC use 'include_next'

#elif defined(BSLS_PLATFORM_CMP_HP) // HP Compiler
#   define BSL_NATIVE_C_LIB_HEADER(filename) <../include_std/filename>

#else
  // Most other compilers
#   define BSL_NATIVE_C_LIB_HEADER(filename) <../include/filename>

#endif
Run Code Online (Sandbox Code Playgroud)

资源

问题是Visual Studio 2015 引入了一些重构,将一些 C标准库头文件移动到这样的路径:C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt.这显然意味着 <../include/filename>将不再找到移动的文件.问题是所有文件都没有移动.例如,iso646.h …

c c++ macros visual-studio

8
推荐指数
1
解决办法
796
查看次数

C计算参数总大小的函数

我目前正在寻找计算传递给函数的参数的总大小,以字节为单位.从理论上讲,人们可以sizeof(x)为每一个论点写出来.但是,如果想要为很多功能执行此操作,这将浪费大量时间.我试图找出参数的空间量,这样我就可以分配适量的内存来存储它们并存储它们(适用于各种函数,混合类型).

我正在寻找一个表达式,可以确定非变量函数的所有参数的大小,无论它们的名称如何,无论有多少(在合理范围内,我现在只支持大约64个参数).它可以是一个函数,一个预处理器宏,我对实现是不可知的.我也有兴趣处理可变参数函数,但我很确定这是不可能的,因为当你进入可变参数函数时,你已经丢失了有关数据类型的所有信息.

目前,我发现有三种方法可能会让我这样做.第一个是基于Laurent Deniau的arg计数的概念.从理论上讲,我可以使用一个宏来生成函数头,并做一些类似花哨的步法来获取args的数量并调度到处理每个具有N个参数的个别情况的宏.(见:丑陋).基本上,我只是使用宏对所有函数名称进行别名,然后在每个函数名称上使用sizeof.问题是,我需要为我想要表示的每个参数长度创建一个宏.而且我真的不喜欢做64(或更多)的事情去做一份工作.

第二种方法是尝试遵循Ben Klemer的"更好的可变参数"的方法.我不会使用他的所有方法,但我会尝试生成一个结构,表示函数的arg签名到结构中.然后,我可以尝试获得结构元素的大小(甚至结构本身,如果我所关心的是对空间的保守估计).这有一些问题.首先,它可能只适用于C99兼容的东西(仍在检查).其次,它为每个实现的功能创建了一个额外的结构.这不完全是一个问题,但它仍然存在这样的问题:他的构造结构的方法最终与函数的名称相同(所以你仍然需要引用名称来使用它们).我可能会解决这个问题.

可能的第三种方法是递归宏,但我不确定编译器有多开心.从理论上讲,通过调用表单中的宏来递归地从VA_ARGS中弹出元素是可能的.很明显,当VA_ARG为空时需要暂停规则(以及确保你没有被浮动+符号捕获的东西),但是你明白了.POPPER(arg, ...) POPPER(VA_ARGS) + sizeof(arg)

这些东西中的任何一个都可以让我这样做:

  1. 从可变参数宏中解压缩VA_ARGS的好方法.如果有任何方法可以索引它
  2. 可以依赖的递归宏的一个很好的例子(以及它在max#of args,编译器兼容性,标准兼容性等方面的限制).
  3. 通过不同类型的功能检查直接获取所有args的总大小的方法.GCC似乎有一些疯狂的函数来构造可能适用的调用转发函数调用,但这些函数是特定于编译器的,几乎没有记录,并且似乎没有报告它们分配的内存块的大小.他们还报告了大量无关的信息.

c macros sizeof c-preprocessor variadic-macros

7
推荐指数
1
解决办法
812
查看次数