用于更复杂函数的C宏

用于更复杂函数的C宏,c,macros,C,Macros,我见过一些简单的宏示例,但对更复杂的东西感到疑惑,比如if语句和重新分配给定变量。像这样更复杂的表达式可以在宏中完成吗?我有一个可以运行数十亿次的函数,所以最好让预处理器把代码扔进去,而不是来回传递变量 假设我有以下功能: int foo(int a, int b, int c){ if (a > 2) c = a; if (b > 3) c = b; return a + b + c; } 如何将其转换为宏?虽然可以用宏替换函数,但很可能对性能没

我见过一些简单的宏示例,但对更复杂的东西感到疑惑,比如if语句和重新分配给定变量。像这样更复杂的表达式可以在宏中完成吗?我有一个可以运行数十亿次的函数,所以最好让预处理器把代码扔进去,而不是来回传递变量

假设我有以下功能:

int foo(int a, int b, int c){  
if (a > 2)  
  c = a;  
if (b > 3)  
  c = b;  

return a + b + c;  
}

如何将其转换为宏?

虽然可以用宏替换函数,但很可能对性能没有影响。任何合理的编译器都会将函数内联移动,如果它认为这会有所帮助。

虽然可以用宏替换函数,但很可能对性能没有影响。任何合理的编译器都会将函数内联移动,如果它认为这会有所帮助。

简单-不要使用宏-只使用内联函数:

__inline int foo(int a, int b, int c)
{  
    if (a > 2)  
        c = a;  
    if (b > 3)  
        c = b;  
    return a + b + c;  
}

简单-不使用宏-只使用内联函数:

__inline int foo(int a, int b, int c)
{  
    if (a > 2)  
        c = a;  
    if (b > 3)  
        c = b;  
    return a + b + c;  
}

如果它看起来应该是一个函数,那么就把它变成一个函数


随着时间的推移,编译器技术已经足够好了,所以您不必担心这样的事情。信任你的编译器,你会没事的。

如果它看起来应该是一个函数,那么就把它变成一个函数


随着时间的推移,编译器技术已经足够好了,所以您不必担心这样的事情。相信你的编译器,你会没事的。

注意宏与函数调用不同-宏实际上会替换使用它们的C源代码,而不是调用和返回-因此可能会有很多意想不到的行为!您的示例可以制作成如下所示的宏:

#define FOO(a,b,c)((a)+(b)+(((b)>3)?(b):((a)>2)?(a):(c)))
但同样也存在一些问题,例如运算符优先级不明确和重复的自动递增/递减运算符


最好还是听从其他答案的建议,使用复杂宏以外的替代策略。

请注意,宏与函数调用不同-宏实际上会替换使用它们的C源代码,而不是调用和返回-因此可能会出现许多意外行为!您的示例可以制作成如下所示的宏:

#define FOO(a,b,c)((a)+(b)+(((b)>3)?(b):((a)>2)?(a):(c)))
但同样也存在一些问题,例如运算符优先级不明确和重复的自动递增/递减运算符



最好还是听从其他答案的建议,使用比复杂宏更好的替代策略。

嗯。你到底想干什么?为什么让它成为一个宏会改变任何事情。现在没有理由使用宏——如果调用开销很大,那么就使用内联函数,但自C89以来就不需要宏,而且宏有许多缺点和陷阱。@保罗:宏是用C进行泛型编程的唯一方法。如果OP想要这样的函数呢在任何组合中,哪个对int、long和double参数有效?@R..:那么OP应该在问题中提到这一点-就我所知,这不是一般编程。我同意宏在这里是无用的。我想我错过了保罗评论中关于这个的主题。你到底想干什么?为什么让它成为一个宏会改变任何事情。现在没有理由使用宏——如果调用开销很大,那么就使用内联函数,但自C89以来就不需要宏,而且宏有许多缺点和陷阱。@保罗:宏是用C进行泛型编程的唯一方法。如果OP想要这样的函数呢在任何组合中,哪个对int、long和double参数有效?@R..:那么OP应该在问题中提到这一点-就我所知,这不是一般编程。我同意宏在这里是无用的。我想我错过了保罗在评论中对此的解释。@Alexandre:也许你可以发布一个答案,解释为什么回答他的问题是一个坏主意?为什么投反对票?在我看来这是正确的。不管危险与否,他回答了这个问题。@maerics:参数会被计算多次,因此如果您将x++传递给a,那么x会递增3次,并且您有未定义的行为,并且它无法检测到传递的参数类型不正确,举两个原因。@maerics:您上面定义的宏有很多问题,例如,你甚至没有在a、b和c的周围加上括号,所以如果其中任何一个是表达式,它都会以惊人的方式失败。更不用说副作用,多重评价等等。我同意。我在谷歌上搜索了宏是邪恶的,点击了12900次。但后来我在谷歌上搜索了答案,得到了400多万美元但说真的,我同意你们所有人的看法,这是一个坏主意,只是一个严厉的否决票。@Alexandre:也许你们可以发布一个答案,解释为什么回答他的问题是一个坏主意?为什么否决票?在我看来这是正确的。不管危险与否,他回答了这个问题。@maerics:参数会被计算多次,所以如果你将x++传递给a,那么x会得到增量
有两个原因,一个是未定义的行为,一个是未定义的行为,另一个是未检测到传递的参数类型不正确。@maerics:您上面定义的宏有很多问题,例如,您甚至没有在a、b和c之间加括号,所以如果其中任何一个是表达式,它将以惊人的方式失败。更不用说副作用,多重评价等等。我同意。我在谷歌上搜索了宏是邪恶的,点击了12900次。但后来我在谷歌上搜索了答案,得到了400多万美元但说真的,我同意你们所有人的看法,这是一个坏主意,只是一个严厉的否决票。或者如果你有一个严肃的C编译器,使用内联而不是内联。并不是说将函数内联标记实际上对它是否由一个合适的编译器内联有很大影响,而是内联函数的定义存在于包含调用的TU中这一事实确实如此。@Steve:的确,内联对于C代码来说更安全、更可移植,但大多数现代/合适的编译器都会识别内联,虽然这可能需要一个命令行开关才能启用。这取决于您所说的可移植。如果给定的编译器不支持内联,那么谁知道它不支持当前C标准的其他部分呢?如果您想编写可移植回C89的代码,那么就不能依赖任何工具来实现内联函数,最好的办法通常是定义一个MY_STATIC_内联宏,该宏将在C99中定义为静态内联,在纯C89中定义为静态,在可用的情况下,还可以定义一些特定于编译器的内联功能;它的使用具有未定义的行为,因为名称是为实现保留的。内联是安全的,因为如果您的编译器是C99之前版本的,您可以简单地定义内联来省略它,或者定义内联来使用一些编译器特定的内联关键字。@R:inline在C99之前的代码中不是完全安全的-您不能简单地定义它,因为可能存在函数、变量,如果您有一个认真的C编译器,请使用inline而不是uu inline。并不是说将函数内联标记实际上对它是否由一个合适的编译器内联有很大影响,而是内联函数的定义存在于包含调用的TU中这一事实确实如此。@Steve:的确,内联对于C代码来说更安全、更可移植,但大多数现代/合适的编译器都会识别内联,虽然这可能需要一个命令行开关才能启用。这取决于您所说的可移植。如果给定的编译器不支持内联,那么谁知道它不支持当前C标准的其他部分呢?如果您想编写可移植回C89的代码,那么就不能依赖任何工具来实现内联函数,最好的办法通常是定义一个MY_STATIC_内联宏,该宏将在C99中定义为静态内联,在纯C89中定义为静态,在可用的情况下,还可以定义一些特定于编译器的内联功能;它的使用具有未定义的行为,因为名称是为实现保留的。内联是安全的,因为如果您的编译器是C99之前版本的,您可以简单地定义内联来省略它,或者定义内联_内联来使用一些编译器特定的_内联关键字。@R:inline在C99之前的代码中不是完全安全的-您不能简单地定义它,因为名为inline的代码中可能存在函数、变量等。