天道酬勤,学无止境

Is it possible to pass a block of code as a macro argument?

I'd like to wrap some lines of code with some boilerplate code, so should I do it by passing multiple lines of code as a macro argument like so:

#define safeRun(x) if (ValidationOK()) {x} 

int main(int argc, char **argv) {
    safeRun(
        foo();
        bar();
    )
}

Many thanks.

标签

评论

As written, your code will run foul of comma operators (but not, as previously claimed, commas in a function argument list).

Assuming you use C99, you can evade even that problem with variable arguments in the macro:

#define safeRun(...) if (ValidationOK()) {__VA_ARGS__}

int main(int argc, char **argv) {
    safeRun(
        foo(a, b),
        bar(c, d);
    )
}

Now, as far as the preprocessor is concerned, there are 2 arguments to the macro, separated by the commas, but they are handled as you want. Here's the gcc -E output:

# 1 "x3.c"
# 1 "<command-line>"
# 1 "x3.c"


int main(int argc, char **argv) {
    if (ValidationOK()) {foo(a, b), bar(c, d);}



}

Whether what you're proposing is a good idea is a separate discussion; these are the mechanisms that will more or less make it work.

Use the \ character to "escape" newlines inside the macro definition. Use variadic macro arguments to support commas inside the argument containing the lines of code. (This feature is part of C99, but also exists in many noncompliant compilers.)

#define safeRun(...) \
[Validation code]; \
if (ValidationOK()) \
    {__VA_ARGS__} \
[Finishing code]; \
/* bumper line to support last backslash, leave empty! */

Note that there cannot be whitespace between the backslash and the newline.

Standard caveat: macros are the leakiest form of encapsulation; use any other construct if possible.

As @Potatoswatter says you can use backslashes:

#define safeRun(x) \
  [Validation code]; \
  if (ValidationOK()) \
      {x} \
  [Finishing code]; \

But this can be a problem if you use it in this way:

if (x)
  safeRun(y);
else
  ...

To fix the problem:

#define safeRun(x) \
  do { \
      [Validation code]; \
      if (ValidationOK()) \
          {x} \
      [Finishing code]; \
  } while(0);

Function-like macros are very bad for a number of reasons. A much better way to solve this is to use real functions.

start_safe();
  foo();
  bar();
stop_safe();

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 用C语言中的宏创建假函数有多少可能?(How much is it possible to create fake-functions with macros in C?)
    问题 人们总是说宏是不安全的,而且它们没有(直接)对参数进行类型检查,依此类推。 更糟糕的是:发生错误时,编译器会给出固有的和难以理解的诊断信息,因为宏只是一团糟。 是否可以通过进行安全的类型检查,避免典型的陷阱以及以编译器提供正确诊断的方式,以与函数几乎相同的方式使用宏。 我将以肯定的方式回答这个问题(自动回答)。 我想向您展示我针对此问题找到的解决方案。 将使用并遵守标准C99,以具有统一的背景。 但是(显然有一个“ but”),它将“定义”人们必须“吃掉”的某种“语法”。 这种特殊的语法旨在以最简单的方式编写,并以最容易理解和/或处理的方式进行编写,以最大程度地减少不良程序的风险,更重要的是,从编译器获取正确的诊断消息。 最后,它将研究两种情况:“非返回值”宏(简单情况)和“返回值”宏(不简单,但更有趣的情况)。 让我们快速记住宏所产生的一些典型陷阱。 例子1 #define SQUARE(X) X*X int i = SQUARE(1+5); 的预期值i :36.真值i :11(与宏扩展: 1+5*1+5 )。 陷阱! (典型)解决方案(示例2) #define SQUARE(X) (X)*(X) int i = (int) SQUARE(3.9); 的预期值i :15的真值i :11(后宏展开: (int) (3.9)*(3.9)) 陷阱! (典型)解决方案(示例3)
  • 在 C 中将块指令作为宏的参数传递(pass block instruction as macro's argument in C)
    问题 我不知道这是否可能,我想像参数一样在宏中传递指令块。我将向您展示一个示例: #define ADD_MACRO(size, BLOCK){ for(int i=0; i<size; i++){\ BLOCK} } 你怎么看待这件事? 感谢帮助 回答1 给定宏的唯一问题是它不处理BLOCK逗号。 可变参数宏参数允许逗号: #define ADD_MACRO(size, ...) do { for(int i=0; i<size; i++){\ __VA_ARGS__} } while(0) (此外,通常的做法是将语句宏包含在do … while(0)以强制用户包含分号。) (当然,原始问题可能有更好的解决方案。预处理器是一个钝器。这是所述问题的预处理器解决方案。) 回答2 您可以通过简单地在宏中显示一个块,或按照另一个答案中的建议使用可变参数宏来做到这一点。 但是,我不建议为此目的使用宏,因为它往往会使代码的可读性降低,更容易出错并且更难阅读/维护。 相反,对于泛型编程,请考虑使用与所需功能相对应的函数指针。 另一种选择是使用 C11 _Generic宏来创建类型安全的通用代码。 例子: #include <stdio.h> #include <ctype.h> void int_increase (int* item) { (*item)++; } void char
  • pass block instruction as macro's argument in C
    I don't know if that is possible, I want to pass a block of instructions in macro like an argument.I will show you an example: #define ADD_MACRO(size, BLOCK){ for(int i=0; i<size; i++){\ BLOCK} } what do you think about it? thanks for help
  • 在宏观尺度 (2.10) 中使用 LabelDef(Using LabelDef in scala macros (2.10))
    问题 我正在试验 scala 2.10 宏功能。 但是,在某些情况下我无法使用LabelDef 。 在某种程度上,我偷看了编译器的代码,阅读了 Miguel Garcia 论文的摘录,但我仍然被困住了。 如果我的理解是正确的,伪定义将是: LabelDef(labelName, listOfParameters, stmsAndApply)其中 3 个参数是 Trees 和: - labelName是正在定义的标签$L的标识符 - listOfParameters对应于listOfParameters apply发生时传递的参数,如$L(a1,...,an) ,并且可以为空 - stmsAndApply对应于语句块(可能没有)和最终apply -expression label-apply 或多或少意味着标签的 GOTO 例如,在一个简单循环的情况下,一个 LabelDef 最终可以应用自己: LabelDef($L, (), {...; $L()}) 现在,如果我想定义 2 个相互跳转的 LabelDef: ... LabelDef($L1, (), $L2()) ... LabelDef($L2, (), $L1()) ... 第二个 LabelDef 很好,但是编译器在第一个输出错误,“未找到:值$L2 ”。 我想这是因为$L2在尝试应用时尚未定义。 这是一棵正在建造的树
  • 如何在objective-c中将块作为宏的参数传递?(how to pass block as a macro's argument in objective-c?)
    问题 在我的代码中,我有很多代码,例如: if (block) block(....) 所以我想定义一个宏,比如 #define safetyCall(block, ...) if((block)) {block(##__VA_ARGS__)}; 但我无法让它工作。 任何想法? 回答1 你不需要##和; 需要搬家: #define safetyCall(block, ...) if((block)) { block(__VA_ARGS__); } 回答2 如果您的块是内联的并且包含具有一系列逗号分隔字符串等的代码,这可能会遇到问题。 例子: safetyCall(^void() { NSArray *foo = @[@"alice", "bob"]; }; 编译器会抱怨“Expected ']' or '.'”和“Expected identifier or '('”。 但是,如果您在宏之前将内联块声明为单独的块,则不会产生错误。 例子: void (^fooBlock)(void) = ^void() { NSArray *foo = @[@"alice", @"bob"]; } safetyCall(fooBlock);
  • 函数声明中的最大参数数(Maximum number of parameters in function declaration)
    问题 我知道函数定义中的最小参数数为零,但是函数定义中的最大参数数是多少? 我问这个问题只是为了知识和好奇心,而不是我要写一个真正的函数。 回答1 是的,实施存在限制。 您的答案在以下 C++ 标准摘录中以粗体文本形式给出。 1. C++语言 附件 B - 实施数量 由于计算机是有限的,C++ 实现不可避免地受限于它们可以成功处理的程序的大小。 每个实施都应记录那些已知的限制。 该文档可能会引用存在的固定限制,说明如何根据可用资源计算可变限制,或者说固定限制不存在或未知。 这些限制可能会限制数量,包括以下描述的数量或其他数量。 建议将每个数量后面的括号数字作为该数量的最小值。 然而,这些数量只是指导方针,并不能确定合规性。 — 复合语句、迭代控制结构和选择控制结构的嵌套级别 [256]。 — 条件包含的嵌套级别 [256]。 — 指针、数组和函数声明符(任意组合)修改声明中的算术、结构、联合或不完整类型 [256]。 — 在完整表达式中嵌套括号表达式的级别 [256]。 — 内部标识符或宏名称中的字符数 [1 024]。 — 外部标识符中的字符数 [1 024]。 — 一个翻译单元中的外部标识符 [65 536]。 — 在一个块中声明的具有块作用域的标识符 [1 024]。 — 在一个翻译单元中同时定义的宏标识符 [65 536]。 — 一个函数定义中的参数 [256]。 —
  • 是否可以使用Rust宏在程序上声明变量?(Is it possible to declare variables procedurally using Rust macros?)
    问题 基本上,这个问题有两个部分: 您可以将未知的标识符传递给Rust中的宏吗? 您可以在Rust宏中组合字符串以生成新的变量名吗? 例如,类似: macro_rules! expand( ($x:ident) => ( let mut x_$x = 0; ) ) 显然,调用expand!(hi)失败,因为hi是未知标识符; 但是你能以某种方式做到这一点吗? IE。 在C中相当于以下内容: #include <stdio.h> #define FN(Name, base) \ int x1_##Name = 0 + base; \ int x2_##Name = 2 + base; \ int x3_##Name = 4 + base; \ int x4_##Name = 8 + base; \ int x5_##Name = 16 + base; int main() { FN(hello, 10) printf("%d %d %d %d %d\n", x1_hello, x2_hello, x3_hello, x4_hello, x5_hello); return 0; } 为什么这么说,这是一个多么糟糕的主意。 你为什么要这么做? 我很高兴你问! 考虑以下防锈块: { let marker = 0; let borrowed = borrow_with_block
  • how to pass block as a macro's argument in objective-c?
    In my code i have a lot of code like: if (block) block(....) So I want to define a macro, something like #define safetyCall(block, ...) if((block)) {block(##__VA_ARGS__)}; But i couldn't get it to work. Any idea?
  • Using LabelDef in scala macros (2.10)
    I'm experimenting with the scala 2.10 macro features. I have trouble using LabelDef in some cases, though. To some extent I peeked in the compiler's code, read excerpts of Miguel Garcia's papers but I'm still stuck. If my understanding is correct, a pseudo-definition would be: LabelDef(labelName, listOfParameters, stmsAndApply) where the 3 arguments are Trees and: - labelNameis the identifier of the label $L being defined - listOfParameters correspond to the arguments passed when label-apply occurs, as in $L(a1,...,an), and can be empty - stmsAndApplycorresponds to the block of statements
  • 宏可以匹配常量参数而不是文字吗?(Can macros match against constant arguments instead of literals?)
    问题 给定宏匹配示例,这显示了宏如何匹配参数。 我在这里做了非常小的改动来使用数字: macro_rules! foo { (0 => $e:expr) => (println!("mode X: {}", $e)); (1 => $e:expr) => (println!("mode Y: {}", $e)); } fn main() { foo!(1 => 3); } 作品,打印: mode Y: 3 但是我想使用一个常量作为参数,这可以起作用吗: const CONST: usize = 1; macro_rules! foo { (0 => $e:expr) => (println!("mode X: {}", $e)); (1 => $e:expr) => (println!("mode Y: {}", $e)); } fn main() { foo!(CONST => 3); } 这在 Rust 中可能吗? 请注意,使用常规match语句对我来说不可用,因为在我的代码中,每个分支都解析为不同的类型,从而产生错误。 所以我特别想知道是否可以将常量传递给宏。 回答1 不。 宏在抽象语法树上运行,因此它们在句法级别进行推理:它们对标记及其拼写进行推理。 例如: fn main() { let v = 3; } 在这种情况下,AST 将类似于: fn main \_ let
  • 编写一个包含匹配体的宏(Writing a macro that contains a match body)
    问题 我试图浓缩一些具有类似于以下结构的重复代码: match self.foo() { None => self.bar(), Some(MyStruct { foo: x, .. }) => match x { Pattern1 => result, Pattern2 => { block_result } } } 我想写成这样: my_macro!( Pattern1 => result, Pattern2 => { block_result } ) 避免重复的None处理和MyStruct解构。 这看起来应该很简单,因为它本质上只是将宏体替换为匹配表达式,但我实际上看不到任何方法来做到这一点。 我尝试按如下方式编写宏: macro_rules! my_macro ( ($($pat:pat => $result:expr,)*) => ( match self.foo() { None => self.bar(), Some(MyStruct { foo: x, .. }) => match x { $( $pat => $result, )* }, } ); ) 但这失败了,因为匹配臂的 RHS 可以是表达式或块(并且它也不处理可选地省略最后一个臂的逗号)。 据我所知,无法指定宏模式的一部分可以是块或表达式,所以我想不出解决这个问题的方法。 理想情况下
  • In Jinja2, how can I use macros in combination with block tags?
    I'm a front end developer, and I've been trying to get a hang on using Jinja2 effectively. I want to tweak a current site so it has multiple base templates using inheritance, it fully uses block tags to substitute content and override it, and uses macros to support passing of arguments. My base template contains this code (edited for simplicity): <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> {% from "foo.html" import macro1, macro2, macro3 %} {% macro base_template(title=none, arg2=none, urls={}, arg3=false) %} <html> <title>{{ title }} | Site.com<
  • 如何编写通用 C 函数来调用 Win32 函数?(How can I write a generic C function for calling a Win32 function?)
    问题 为了允许从脚本语言(用 C 编写)访问 Win32 API,我想编写一个函数,如下所示: void Call(LPCSTR DllName, LPCSTR FunctionName, LPSTR ReturnValue, USHORT ArgumentCount, LPSTR Arguments[]) 它通常会调用任何 Win32 API 函数。 (LPSTR 参数基本上用作字节数组 - 假设它们的大小已正确调整以采用函数外部的正确数据类型。此外,我相信需要一些额外的复杂性来区分指针和非指针参数,但我'我忽略了这个问题的目的)。 我遇到的问题是将参数传递给 Win32 API 函数。 因为这些是 stdcall 我不能使用 varargs 所以'Call'的实现必须提前知道参数的数量,因此它不能是通用的...... 我想我可以用汇编代码来做到这一点(通过循环参数,将每个参数推到堆栈中)但这在纯 C 中可能吗? 更新:我已将“不,这是不可能的”答案标记为目前已接受。 如果基于 C 的解决方案出现,我当然会改变这一点。 更新: ruby/dl 看起来可以使用合适的机制来实现。 任何有关这方面的细节将不胜感激。 回答1 首先要做的事情是:您不能在 C 中将类型作为参数传递。剩下的唯一选择是宏。 如果您正在执行LoadLibrary/GetProcAddress来调用 Win32
  • 在 Jinja2 中,如何将宏与块标记结合使用?(In Jinja2, how can I use macros in combination with block tags?)
    问题 我是一名前端开发人员,我一直在尝试有效地使用 Jinja2。 我想调整当前站点,使其具有多个使用继承的基本模板,它完全使用块标记来替换内容并覆盖它,并使用宏来支持参数传递。 我的基本模板包含以下代码(为简单起见进行了编辑): <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> {% from "foo.html" import macro1, macro2, macro3 %} {% macro base_template(title=none, arg2=none, urls={}, arg3=false) %} <html> <title>{{ title }} | Site.com</title> .... {{ caller() }} .... </html> {% endmacro %} {% block content %}{% endblock %} 我扩展它的页面如下所示: {% extends "base.html" %} {% block content %} {% call base_template(title="home", arg2="active", arg3="true") %} (html code here) {
  • Is it possible to prevent duplicate, identical arguments to a macro in C?
    There are certain rare cases, it may be useful to prevent duplicate arguments to a macro. Take this ELEM(value, ...) macro, To check if value is either A, B or C. if (ELEM(value, A, B, C)) { .... } Someone could, by accident passes in the same argument multiple times, eg: if (ELEM(value, A, B, B)) { .... } While valid C, but almost certainly an accident, and highly unlikely to be what the developer intended. ... this is of course a trivial example, actual error cases would be more complicated. Question Is there a way to have the compiler warn/errorwhen passing in duplicate arguments
  • 有没有一种方法可以在C中实现闭包(Is there a a way to achieve closures in C)
    问题 我想这样做,但它不能: #include <stdio.h> typedef struct closure_s { void (*incrementer) (); void (*emitter) (); } closure; closure emit(int in) { void incrementer() { in++; } void emitter() { printf("%d\n", in); } return (closure) { incrementer, emitter }; } main() { closure test[] = { emit(10), emit(20) }; test[0] . incrementer(); test[1] . incrementer(); test[0] . emitter(); test[1] . emitter(); } 它实际上确实可以编译并且可以在1个实例中工作……但是第二个实例却失败了。 知道如何在C中获得闭包吗? 真是太棒了! 回答1 使用FFCALL, #include <callback.h> #include <stdio.h> static void incrementer_(int *in) { ++*in; } static void emitter_(int *in) { printf("%d\n"
  • 技巧:使用宏填充数组值(代码生成)(Trick : filling array values using macros (code generation))
    问题 C++ 模板只是伪装的宏吗? 我正在阅读上面的主题,突然想到这个想法:为什么不尝试编写一些可以在我们的真实代码中使用的棘手的宏(不仅仅是作为在现实生活中无用的谜题)? 所以首先想到的是:用宏填充数组值: int f(int &i) { return ++i; } #define e100 r5(m20) #define m20 m5,m5,m5,m5 #define m5 r5(e1) #define e1 f(i) //avoiding ++i right here, to avoid UB! #define r5(e) e,e,e,e,e int main() { int i=0; //this is used in the macro e1 int a[] = {e100}; //filling array values with macros! int n = sizeof(a)/sizeof(int); cout << "count = " << n << endl; for(int i = 0 ; i < n ; i++ ) cout << a[i] << endl; return 0; } 输出: count = 100 1 2 3 4 . . . 100 在线演示:http://www.ideone.com/nUYrq 我们能否在紧凑性或通用性
  • Swift +宏参数(Swift + macro parameters)
    问题 我阅读了Swift所有与宏相关的问答,而且我确实弄清楚了everything in Swift now global,中的everything in Swift now global,对吗? 我的实际问题是,如果我有一个需要传递参数的宏,那么我该如何以Swift语言传递它呢? 例如 Objective-C巨集 #define COLOR_CODE(red, green, blue, alpha) [UIColor colorWithRed: red/255.0 green: green/255.0 blue: blue/255.0 alpha: alpha] 上述宏的Swift语法是什么? 回答1 如0O0O0O0所述,宏的含义是“编译器应看到COLOR_CODE(0, 0, 0, 1)并将其替换为[UIColor colorWithRed: 0/255.0 green: 0/255.0 blue: 0/255.0 alpha: 1] ”在Swift中不存在。 可以使用C语言中的宏来产生令人困惑的错误消息: #define IS_EQUAL_TO_ME(argument) [self isEqual: argument] BOOL func(id argument) { return IS_EQUAL_TO_ME(argument); } // Error: Use of
  • 任何人都可以在以下示例中解释 C 预处理器的行为吗?(Can anybody please explain the behavour of C preprocessor in following examples?)
    问题 我正在实现一个 C 宏预处理器(C99)... 我对以下行为感到惊讶...... 例1: #define PASTE(x) X_##x #define EXPAND(x) PASTE(x) #define TABSIZE 1024 #define BUFSIZE TABSIZE PASTE(BUFSIZE) EXPAND(BUFSIZE) 扩展为: X_BUFFSIZE X_1024 例2: #define EXPAND(s) TO_STRING(s) #define TO_STRING(s) #s #define FOUR 4 TO_STRING(FOUR) EXPAND(FOUR) 扩展为: "FOUR" "4" 我已经通过了 C 的“免费”标准,但我找不到以下内容...... 实际上预处理器执行了多少遍? 它是否先替换一个宏然后另一个宏等等或者它是否存储和替换它们,因为#define s 一一遇到? 文件包含是先完成还是宏扩展? 回答1 您应该阅读此页面作为初学者。 它包含宝石,例如: C 标准规定,在任何参数被其可能扩展的参数替换后,将扫描替换列表以查找嵌套宏。 此外,在此扫描期间未扩展的替换列表中的任何标识符在将来不再有资格进行扩展,如果它们未扩展的原因是所讨论的宏被禁用。 我认为可以从中推断出没有固定的传递次数:每次发生宏扩展(生成“替换列表”)时
  • 在C99中,f()+ g()是未定义的还是仅仅是未指定的?(In C99, is f()+g() undefined or merely unspecified?)
    问题 我曾经认为在C99中,即使函数f和g的副作用受到干扰,并且尽管表达式f() + g()不包含序列点,但f和g会包含一些点,因此行为会不确定:在g()之前调用f(),或者在f()之前调用g()。 我不再那么确定。 如果编译器内联函数(即使未将函数声明为inline ,编译器可能会决定这样做)然后重新排序指令怎么办? 可以得到与以上两个不同的结果吗? 换句话说,这是未定义的行为吗? 这不是因为我打算写这种东西,而是为了在静态分析器中为这样的语句选择最佳标签。 回答1 表达式f() + g()至少包含4个序列点; 在调用f()之前一个(在对它的所有零个参数求值之后); 在调用g()之前一个(在其所有零个参数都被求值之后); 当f()的调用返回时返回一个; 一个作为对g()的调用返回。 此外,与f()关联的两个序列点出现在与g()关联的两个序列点之前或之后。 您无法确定序列点将以什么顺序出现-f点是出现在g点之前,还是反之亦然。 即使编译器内联了代码,它也必须遵守“好像”规则-代码的行为必须与未交织函数的行为相同。 这就限制了损坏的范围(假设编译器为非越野车)。 因此,未指定计算f()和g()的顺序。 但是其他一切都很干净。 在评论中,supercat问: 我希望即使编译器自己决定内联它们,源代码中的函数调用仍保留为序列点。 声明为“内联”的函数是否仍然适用