使用预处理器定义函数调用的缺点是什么?
我想知道以这种方式使用预处理器的缺点是什么:
#define SOME_FUNCTION someFunction(someArgument)
基本上我觉得这是错误的(或者肯定不是最佳实践) - 但我不确定为什么......我的预处理器技能生锈了最好的。
I would like to know what the cons are of using the preprocessor in such a way:
#define SOME_FUNCTION someFunction(someArgument)
Basically I feel like this is wrong (or certainly not a best practice) - but I'm not sure why... my preprocessor skills are rusty at best.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
问题是每次使用参数时都会重新计算它们:
请注意,我必须将所有参数包装在 '(' ')' 中以确保表达式正确计算。但如果我们这样做会发生什么呢?
对此进行编码时,我希望电流在调用该函数之前增加一次。但因为它是一个宏,所以在测试中会增加一次,如果它仍然小于 Max,则会增加第二次
The problem is that the arguments are re=evaluated each time they are used:
Notice that I have to wrap all the arguments in '(' ')' to make sure the expression evaluates corectly. But what happens if we do this?
Coding this I would expect current to be incremented once before the function is called. But because it is a macro it is incremented once in the test and a second time if it is still smaller than Max
缺点?通常宏定义不会出现在可执行文件的符号表中。调试起来稍微困难一些。
A downside? Usually a macro definition doesn't end up in the executable's symbol table. Slightly more difficult to debug.
您可以想到几个问题:
如果您正在为 Windows 编程并包含 windows.h 并想要编写 std::numeric_limits::max() 那么 max 将被一些代码替换...这会在预处理器运行后留下无法编译的代码。 (好吧,有一些方法可以关闭 windows.h 中的最小/最大宏,但它仍然是糟糕的设计!)
There are several problems you can think of:
If you are programming for windows and include windows.h and want to write std::numeric_limits::max() then max will be replaced by some code... This leaves uncompilable code after preprocessor run. (Okay there are ways to turn off min/max macros in windows.h but it's still poor design!)
好吧,如果你必须这样做(并且在某些情况下你可能会这么做),那么你至少应该将宏定义为“类似函数”:
否则你会编写看起来像常量赋值的代码。事实上是一个函数调用; IE;
但是对于“类似函数”的宏,您将不得不编写:
哪个更好地匹配预处理器语法与语言语法。
一般来说,最好避免使用类似函数的宏,但有些宏比其他宏更阴险,这绝不是最坏的情况。但是,您可以轻松地用 C 编写函数包装器,或者在 C++ 中使用默认参数,这在大多数情况下会更可取。
Well if you must do that (and there are some occasions when you might), then you should at least define the macro as "function-like" thus:
otherwise you would write code that looked like an assignment by a constant when it was in fact a function call; i.e;
but with a "function-like" macro you would be obliged to write:
Which better matches the pre-processor syntax with the language syntax.
Generally function-like macros are best avoided, but some are more insidious that others, this is by no means the worst case. However, you might just as easily write a function wrapper in C, or in C++ use a default argument, and this would be preferable in most cases.
在非常封闭的领域中,这有时很有用,可以以更易读的方式定义流程步骤:
但通常它只会使代码更难以阅读和理解。
除非代码的读者值得详细了解这些 #define 的含义,并且这是某种捷径,否则您只是让人们查看两个地方来理解一行代码(文件顶部和文件中)函数)而不是一个。
我很少使用这种方法。
This is occasionally useful in a very closed domain for defining process steps in a more readable fashion:
But usually it just makes code harder to read and understand.
Unless its worth the readers of your code getting to know what those #define's mean in detail, and it's some kind of short cut, you're just getting people to look in two places to understand a line of code (top of file and in function) rather than one.
I very rarely use this kind of approach.
这将取决于语言、编译器等,等等...
但是,这没有任何问题,正如名称所暗示的那样,这些指令发生在编译过程之前。
预处理器通过其实际值删除所有常量引用,具有正确代码的所有伪函数,等等......
That will depend on the language, compiler, etc, etc, etc...
However, there's nothing wrong with it, once as the name implies those directives occurs PREviously the PROCESS of compiling.
The pre-processor removes all constant references by its real value, all the pseudo-function with the proper code, and so on...
这是这些额外的间接级别之一:-)
假设在某个时候该函数需要另一个参数或者您根本不需要调用它,您可以更改
#define
一次而不是更改调用该函数的所有位置。对于开发很有用,但保留在生产代码中很危险......一旦我有了成熟的代码并且知道我不需要更改它,我就会运行预处理器来替换该规则。
This is one of these extra indirection levels :-)
Say that at some point that function needs another argument or you don't need to call it at all, you can change the
#define
once instead of changing all the places where the function is being called.Useful for developing, but dangerous to keep in production code... I'd run the preprocessor to replace that rule once I have a mature code and know that I won't need to change it.
为什么要寻找使用特定预处理器代码的缺点?将预处理器宏用于除条件编译(包括包含防护)之外的任何内容都应该被自动视为不好的。正确的问题是特定用途是否有优势。
预处理器宏不以任何方式尊重范围或用法。他们可能会以意想不到的且难以找到的方式搞砸完美的代码。始终避免使用它们,除非您有充分的理由使用它们。
Why would you look for disadvantages in using specific preprocessor code? Using preprocessor macros for anything other than conditional compilation (including include guards) should be automatically considered bad. The correct question to ask is whether there are advantages to a particular use.
Preprocessor macros don't respect scope or usage in any way. They can screw up perfectly good code in unexpected and difficult-to-find ways. Always avoid them unless you've got a good reason to use one.
缺点是你隐藏了代码。
好处是你隐藏了代码。
负面影响通常超过正面影响。
通常这种特殊的方法几乎没有用处,除非调用看起来更像
someModule->someStorage->functionList[storage.getFunctionName].pointer->SomeFunction(...同样晦涩的参数...);
这样做是没有意义的。如果只有参数是一个晦涩的调用,则仅简写参数。如果只是函数,则仅简写函数。如果两者都是,那么您可能会更好
如果该函数从未用其他任何东西调用,您可能会考虑将其从参数列表中删除并在函数体内获取。如果该对经常重复且变化很小,您可能会考虑包装函数。
当你在宏代码中犯了几个错误之后,你就会知道调试它们是很痛苦的,并且你不会轻率地使用它们。
The downside is that you are hiding the code.
The upside is that you are hiding the code.
The downside usually outweights the upside.
Usually this particular approach is pretty much useless and unless the call looks more like
someModule->someStorage->functionList[storage.getFunctionName].pointer->SomeFunction(...equally obscure argument...);
there is no point doing so. If only the argument is an obscure call, shorthand only the argument. If it's only the function, shorthand only the function. If both, you might be better off with
If the function is never called with anything else, you might consider removing it from argument list and obtaining inside the function body. And if the pair repeats very often, in small variations, you might consider wrapper functions.
After you make several bugs in the code of a macro, you will learn it's pain to debug them and you won't use them frivolously.