6 ms·
Completely agree with no. 5. After a year with C I realized that macros are only to be used as control structures for headers and ifdefs to enable compatibility
by deletes 13y ago
Completely agree with no. 5. After a year with C I realized that macros are only to be used as control structures for headers and ifdefs to enable compatibility.
If you need macros to hack C to enable some functionality not inherent to the language, you should change the approach or switch to a different language.
Also macros are usually used to "speed up" the code. You should never optimize before finding the real bottleneck in your code. And thus always use functions instead of macros.
- Nursie 13y agoMacros enable you to replace things at compile time. The C preprocessor is a powerful and awesome thing by itself and I miss it when it's not available in other languages. It enables you to do things like pass line and file numbers automatically. For instance - #define log_message(format...) _log_message(__FILE__, __LINE__, format) void _log_message(char* filename, int line, char* format, ...); And there's nothing inherently wrong with #define for frequently used magic numbers. They have the advantage of being pre-processed out rather than being separate variables at compile time. Macros are also useful to simplify little repeated chunks of code that don't really need their own function. I've not often seen macros used to try to speed up code. --edit-- I don't know how long you've kept up with your C, but what you've realised after a year with the language doesn't seem as obvious to me after 15.
- theseoafs 13y ago> If you need macros to hack C to enable some functionality not inherent to the language, you should change the approach or switch to a different language. I think if you continue to do serious C hacking, you'll find a lot of places where macros are legitimately a good choice. For example, I've found that macros are very, very useful when it comes to implementing error handling in a robust way. In C, the only real way to detect whether a function has failed is to return an error code. The caller then has to test for the error code and take the appropriate action if there was an error. I'm working on a side project now that was doing a LOT of this because it does a lot of IO and memory allocation (and basically any operation you do on a file or any call to `malloc` or a function that calls `malloc` can spontaneously fail in C). So my source code, after a while, ended up looking more or less like this: if ((f = open_file()) == NULL) return ERROR_CODE; if ((s = allocate_string()) == NULL) return ERROR_CODE; if (write_string_to_file(s, f) < 0) return ERROR_CODE; ... and so on, and so forth. It got to the point where basically all of the function calls I did needed to be manually checked for an error, which made all of my code really messy and hard to read. The only real way to refactor these checks in pure C without sacrificing robustness is to use a macro: #define MY_ASSERT(c) do { if (!(c)) return ERROR_CODE; } while (0) MY_ASSERT((f = open_file()) != NULL); MY_ASSERT((s = allocate_string()) != NULL); MY_ASSERT(write_string_to_file(s, f) >= 0); This has the same effect as the code above, without sacrificing comprehensibility or readability. > Also macros are usually used to "speed up" the code. You should never optimize before finding the real bottleneck in your code. And thus always use functions instead of macros. I think a lot of people on HN and /r/programming fail to understand why premature optimization is a bad thing. A lot of programmers hide behind the "premature optimization is the root of all evil" thing to justify their pre-existing biases or their inefficient code. The point is that you shouldn't spend a great deal of time optimizing functions or algorithms unless optimizing those functions or algorithms will be productive. It's wasteful to spend a bunch of time optimizing your IO operations, for example, if 95% of the time is being spent in the database. The macro-vs-function debate has nothing to do with that. Writing a macro definition takes no more effort than writing a function definition, so you shouldn't be opposed to writing #define SOME_OPERATION(x) (((x) * 100) / 3 + 500) rather than int some_operation(int x) { return (x * 100) / 3 + 500; } That isn't premature optimization, you're just guaranteeing that the compiler won't introduce the overhead of a function call.
- femngi 13y agoI have to strongly disagree with your example. In fact I feel it may just be one of the worst usages of macros I have seen in that you are hiding the control flow of the program and thus obfuscating your code for other programmers. It might be easier for you to read because you wrote it but for every one that comes after you it will be a massive pain that adds unneeded additional cognitive overhead. I say this from the point of view of someone having to debug your code: "OK so step, step, step, run to this line... wait, what? How did this function return when there is no return statement? Let me run that again from the beginning... ... ... What? This ASSERT macro doesn't actually assert it just returns?" Keyboard out window etc. Please stick to language conventions. Macros are bad because they hide what the code is actually doing.
- theseoafs 13y agoTo be fair, I don't see why you would have to throw your keyboard out the window. If I were debugging a source file and saw the same ASSERT macro on every other line, I would break out `grep` and track down the (extremely simple) definition so I could understand what it's doing. Moreover, returning with an error code is IMO entirely sane behavior for a macro with ASSERT in the name, especially considering halting execution of the program altogether generally isn't a good thing if you're writing a C library.
- deletes 13y agoThe point of assert is to check your code has values within your required parameters, so you the code is easier to debug while coding. Asserts should never be left in your code compiled for release. Even c library assert is aware of that, as it has the NDEBUG macro, which removes every assert in the code. That is also the reason why you should Never put code that might mutate your variables in them.( function calls or assigning, for example) http://www.cplusplus.com/reference/cassert/assert/ http://www.cplusplus.com/reference/cassert/assert/ Quote from the link: Therefore, this macro is designed to capture programming errors, not user or run-time errors, since it is generally disabled after a program exits its debugging phase. Of course you can name your macro whatever you want, even assert, but it will confuse other developers used to c library functions.