Is there a way to detect in compilation-time, if a function is built-in on compiler?
e.g, something like this:
#ifndef ITOA_FUNCTION
#define itoa myitoaimplementation
#endif
Thanks in advance.
No, there's not anything direct. About the best you can do is guess from things like the platform, compiler version, etc.
In most cases, I'd prefer one of two other routes though. One is to just give your own implementation a name different from what the compilers use, and always use it whether the compiler provides something similar or not.
The second is to put your implementations of functions like this into a separate file, and deal with the presence/absence in the makefile, just deciding whether to include that file in the project or not.
Related
Are these two Code equal?(clear flag)
ClearFlag(NewDeviceObject->Flags, DO_DEVICE_INITIALIZING);
NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
Yes they are equal.
Unlike APIs, ClearFlag is a macro. You can enter the ntifs.h that you compile with and see it. Microsoft doesn't change macros like this, because then you won't be able to use the same binary on any older windows (which is not something they like). This is why only small utilities like that are inlined.
Anyway it's a much better practice and much cleaner to use the macro, so use it like you use other win macro that won't be changed for same reasons (it's just not a bug not using it).
I'm looking into Flutters embedder API because I might be calling it via Rust in an upcoming project and find this:
FLUTTER_EXPORT
FlutterResult FlutterEngineShutdown(FlutterEngine engine);
The FLUTTER_EXPORT part is (from what I can see) a macro defined as:
#ifndef FLUTTER_EXPORT
#define FLUTTER_EXPORT
#endif // FLUTTER_EXPORT
I'm by no means a C guru but I have done my fair share of C programming but have never had the opportunity to use something like this. What is it? I've tried to Google it but don't really know what to call it other than "annotation" which doesn't really feel like a perfect fit.
Flutter embedder.h
Also as pointed out - these macro can't be expanded to something meaningful - for example if you write this macro couple of time it will affect nothing.
Another nice use can be - (useful in testing of code) from here
You can pass -DFLUTTER_EXPORT=SOMETHING while using gcc. This will be useful in running your code for testing purposes without touching the codebase. Also this can be used in providing different kind of expnasion based on the compile time passed parameter - which can be used in different ways.
Also a significant part of my answer boasts of the visibility using the empty macro, gcc also provides a way to realize the same thing as described here using __attribute__ ((visibility ("default"))) (as IharobAlAsimi/nemequ mentioned) (-fvisibility=hidden) etc for the macro FLUTTER_EXPORT. The name also gives us a idea that it might be necessary to add the attribute __declspec(dllimport) (which means it will be imported from a dll). An example regarding gcc's usage of visibility support over there will be helpful.
It can useful in associating some kind of debug operation like this (By this I mean that these empty macros can be used like this also - though the name suggests that this was not the intended use)
#ifdef FLUTTER_EXPORT
#define ...
#else
#define ...
#endif
Here #define here will specify some printing or logging macro. And if not defined then it will be replaced with something blank statement. do{}while(0) etc.
This is going to be a bit rambling, but I wanted to talk about some stuff that came up in the comments in addition to your initial question.
On Windows, under certain situations the compiler needs to be explicitly told that certain symbols are to be publicly exposed by a DLL. In Microsoft's compiler (heretofore referred to as MSVC), this is done by adding a __declspec(dllexport) annotation to the function, so you would end up with something like
__declspec(dllexport)
FlutterResult FlutterEngineShutdown(FlutterEngine engine);
Alas, the declspec syntax is non-standard. While GCC does actually support it (IIRC it's ignored on non-Windows platforms), other conformant compilers may not, so it should only be emitted for compilers which support it. The path that the Flutter devs have taken is one easy way to do this; if FLUTTER_EXPORT isn't defined elsewhere, they simply define it to nothing, so that on compilers where __declspec(dllexport) is unnecessary the prototype you've posted would become
FlutterResult FlutterEngineShutdown(FlutterEngine engine);
But on MSVC you'll get the declspec.
Once you have the default value (nothing) set, you can start thinking about how to define special cases. There are a few ways to do this, but the most popular solutions would be to include a platform-specific header which define macros to the correct value for that platform, or to use the build system to pass a definition to the compiler (e.g., -DFLUTTER_EXPORT="__declspec(dllexport)"). I'm prefer to keep logic in the code instead of the build system when possible to make it easier to reuse the code with different build systems, so I'll assume that's the method for the rest of the answer, but you should be able to see the parallels if you choose the build-system route.
As you can imagine, the fact that there is a default definition (which, in this case, is empty) makes maintenance easier; instead of having to define every macro in each platform-specific header, you only have to define it in the headers where a non-default value is required. Furthermore, if you add a new macro you needn't add it to every header immediately.
I think that's pretty much the end of the answer to your initial question.
Now, if we're not building Flutter, but instead using the header in a library which links to the Flutter DLL, __declspec(dllexport) isn't right. We're not exporting the FlutterEngineShutdown function in our code, we're importing it from a DLL. So, if we want to use the same header (which we do, otherwise we introduce the possibility of headers getting out of sync), we actually want to map FLUTTER_EXPORT to __declspec(dllimport). AFAIK this isn't usually necessary even on Windows, but there are situations where it is.
The solution here is to define a macro when we're building Flutter, but never define it in the public headers. Again, I like to use a separate header, something like
#define FLUTTER_COMPILING
#include "public-header.h"
I'd also throw some include guards in, and a check to make sure the public API wasn't accidentally included first, but I'm to lazy to type it here.
Then you can define FLUTTER_EXPORT with something like
#if defined(FLUTTER_COMPILING)
#define FLUTTER_EXPORT __declspec(dllexport)
#else
#define FLUTTER_EXPORT __declspec(dllimport)
#endif
You may also want to add a third case, where neither is defined, for situations where you're building the Flutter SDK into an executable instead of building Flutter as a shared library then linking to it from your executable. I'm not sure if Flutter supports that or not, but for now let's just focus on the Flutter SDK as a shared library.
Next, let's look at a related issue: visibility. Most compilers which aren't MSVC masquerade as GCC; they define __GNUC__, __GNUC_MINOR__, and __GNUC_PATCHLEVEL__ (and other macros) to the appropriate values and, more importantly, if they're pretending to be GCC ≥ 4.2 they support the visibility attribute.
Visibility isn't quite the same as dllexport/dllimport. Instead, it's more like telling the compiler whether the symbol is internal ("hidden") or publicly visible ("default"). This is a bit like the static keyword, but while static restricts a symbol's visibility to the current compilation unit (i.e., source file), hidden symbols can be used in other compilation units but they're not exposed by the linker.
Hiding symbols which needn't be public can be a huge performance win, especially for C++ (which tends to expose a lot more symbols than people think). Obviously having a smaller symbol table makes the linking a lot faster, but perhaps more significant is that the compiler can perform a lot of optimizations which it can't or doesn't for public symbols. Sometimes this is as simple as inlining a function which otherwise wouldn't be, but another huge performance gain can come from the compiler being able to assume data from a caller is aligned, which in turn allows vectorization without unnecessary shuffling. Another might allow the compiler to assume that a pointer isn't aliased, or maybe a function is never called and can be pruned. Basically, there are lots of optimizations the compiler can only do if it knows it can see all the invocations of a function, so if you care about runtime efficiency you should never expose more than is necessary.
This is also a good chance to note that FLUTTER_EXPORT isn't a very good name. Something like FLUTTER_API or FLUTTER_PUBLIC would be better, so let's use that from now on.
By default, symbols are publicly visible, but you can change this by passing -fvisibility=hidden to the compiler. Whether or not you do this will determine whether you need to annotate public functions with __attribute__((visibility("default"))) or private functions with __attribute__((visibility("hidden"))), but I would suggest passing the argument so that if you forget to annotate something you'll end up with an error when you try to use it from a different module instead of silently exposing it publicly.
Two other things also came up in the comments: debugging macros and function annotations. Because of where FLUTTER_EXPORT is used, we know it's not a debugging macro, but we can talk about them for a second anyways. The idea is that you can insert extra code into your compiled software depending on whether or not a macro is defined. The idea is something like this:
#if defined(DISABLE_LOGGING)
# define my_log_func(msg)
#else
# define my_log_func(msg) my_log_func_ex(expr)
#endif
This is actually a pretty bad idea; think about code like this:
if (foo)
my_log_func("Foo is true!");
bar();
With the above definitions, if you compile with DISABLE_LOGGING defined, you'll end up with
if (foo)
bar();
Which probably isn't what you wanted (unless you're entering an obfuscated C competition, or trying to insert a backdoor).
Instead, what you usually want is (as coderredoc mentioned) basically a no-op statement:
#if defined(DISABLE_LOGGING)
# define my_log_func(msg) do{}while(0)
#else
# define my_log_func(msg) my_log_func_ex(expr)
#endif
You may end up with a compiler error in some weird situations, but compile-time errors are vastly preferable to difficult-to-find bugs like you can end up with for the first version.
Annotations for static analysis is another situation which was mentioned in the comments, and it's something I'm a huge fan of. For example, let's say we have a function in our public API which takes a printf-style format string. We can add an annotation:
__attribute__((format(2,3)))
void print_warning(Context* ctx, const char* fmt, ...);
Now if you try to pass an int to a %f, or forget an argument, the compiler can emit a diagnostic at compile time just like with printf itself. I'm not going to go into each and every one of these, but taking advantage of them is a great way to get the compiler to catch bugs before they make it into production code.
Now for some self-promotion. Pretty much all this stuff is highly platform-dependent; whether a feature is available and how to use it properly can depend on the compiler, compiler version, the OS, and more. If you like to keep your code portable you end up with a lots preprocessor cruft to get it all right. To deal with this, I put together a project called Hedley a while back. It's a single header you can drop into your source tree which should make it a lot easier to take advantage of this type of functionality without making people's eyes bleed when they look at your headers.
I am trying to do some work on Windows drivers but I am having trouble understanding one part of the example source code. I have never seen this before in my C experience and I couldn't find anything on it. Anyways, I was wondering what the "IN" part of the parameter variables are? Below is an example of the header of a function. It is also possible for it to be a few other things like "OUT", "INOUT", "INOPT", and maybe more (couldn't find anything else).
VOID
PLxReadRequestComplete(
IN WDFDMATRANSACTION DmaTransaction,
IN NTSTATUS Status
)
Those are simply markers (from the early days of the Windows DDK) that describe the intended use of the parameter.
In normal builds the macros are defined as nothing, however they could conceivably be defined to implementation-specific keywords that allow the compiler (using SAL or other static code analysis tools) to perform deeper analysis about the correct use of the argument/parameter. I don't think that they're used for SAL because they simply aren't 'rich' enough to describe all the attributes that SAL likes to take into account. So I think they're mainly intended to communicate intent to programmers.
That's not standard C. Most likely, IN has been defined to have some other value using a #define -- i.e., a macro. Search your *.h files for #define IN, #define OUT, etc, and see if you can find out what.
I am trying to write a generic library in pure c , just some data structures like stack, queue...
In my stack.h when giving name to those functions. I have questions about that.
Can I use such name, for example "init" as the function name to init a stack. Will there be something wrong?
I know maybe there exist other functions which just do other things and have the same name as "init". Then would the program be confused, especially when i both include the different init's headers.
3.I know my worry may be unnecessary, but i still want to know the principle.
Any help is appreciated, thanks.
Can I use such name, for example "init" as the function name to init a
stack. Will there be something wrong?
Yes, if anyone else wants a function named init.
I know my worry may be unnecessary, but i still want to know the
principle
Your worry is necessary, this (the lack of namespaces) is a serious problem in C.
Export as few functions as possible. Make everything static if you can
Prefix function names with something. For instance, instead of init, try stack_init
You don't have namespaces in C so usually you prefix every identifier with the name or nickname of your library.
init();
becomes
fancy_lib_init();
There might be existing libraries doing what you want (e.g. Glib). At least, study them a little before writing your own.
If you claim to develop a generic reusable C library, I suggest having naming conventions. For instance, have all the identifiers (notably function names, typedef-s, struct names...) share some common prefix.
Be systematic in your naming conventions. For instance, initializers for stacks and for queues should have similar names & signatures, and end with _init. Document your naming conventions.
Define very clearly how should data be allocated and released. Who and when should call free?
init() might be okay (if you're including your library into something else as an actual library, rather than compiling its source in), but it's better practice to use something like stack_init(), and to prefix your library's functions with stack_ or queue_, etc.
A program using your library may get confused, depending on the order the libraries are included, see #1.
As far as the principles go, the linker (on Linux, anyway) will look for symbols, and there's an ordering to how those symbols will be found. For more information, you can check out the man page for dlsym(), and specifically for RTLD_NEXT.
Function names in C are global. If two functions in a program have the same name, the program should fail to compile. (Well, sometimes it fails at link time, but the idea still holds.)
Generally, you get around this problem by using some sort of prefix or suffix on the function names in your library. "apporc_stack_init()" is much less likely to collide with something than "init()" is.
A programmer I respect said that in C code, #if and #ifdef should be avoided at all costs, except possibly in header files. Why would it be considered bad programming practice to use #ifdef in a .c file?
Hard to maintain. Better use interfaces to abstract platform specific code than abusing conditional compilation by scattering #ifdefs all over your implementation.
E.g.
void foo() {
#ifdef WIN32
// do Windows stuff
#else
// do Posix stuff
#endif
// do general stuff
}
Is not nice. Instead have files foo_w32.c and foo_psx.c with
foo_w32.c:
void foo() {
// windows implementation
}
foo_psx.c:
void foo() {
// posix implementation
}
foo.h:
void foo(); // common interface
Then have 2 makefiles1: Makefile.win, Makefile.psx, with each compiling the appropriate .c file and linking against the right object.
Minor amendment:
If foo()'s implementation depends on some code that appears in all platforms, E.g. common_stuff()2, simply call that in your foo() implementations.
E.g.
common.h:
void common_stuff(); // May be implemented in common.c, or maybe has multiple
// implementations in common_{A, B, ...} for platforms
// { A, B, ... }. Irrelevant.
foo_{w32, psx}.c:
void foo() { // Win32/Posix implementation
// Stuff
...
if (bar) {
common_stuff();
}
}
While you may be repeating a function call to common_stuff(), you can't parameterize your definition of foo() per platform unless it follows a very specific pattern. Generally, platform differences require completely different implementations and don't follow such patterns.
Makefiles are used here illustratively. Your build system may not use make at all, such as if you use Visual Studio, CMake, Scons, etc.
Even if common_stuff() actually has multiple implementations, varying per platform.
(Somewhat off the asked question)
I saw a tip once suggesting the use of #if(n)def/#endif blocks for use in debugging/isolating code instead of commenting.
It was suggested to help avoid situations in which the section to be commented already had documentation comments and a solution like the following would have to be implemented:
/* <-- begin debug cmnt if (condition) /* comment */
/* <-- restart debug cmnt {
....
}
*/ <-- end debug cmnt
Instead, this would be:
#ifdef IS_DEBUGGED_SECTION_X
if (condition) /* comment */
{
....
}
#endif
Seemed like a neat idea to me. Wish I could remember the source so I could link it :(
Because then when you do search results you don't know if the code is in or out without reading it.
Because they should be used for OS/Platform dependencies, and therefore that kind of code should be in files like io_win.c or io_macos.c
My interpretation of this rule:
Your (algorithmic) program logic should not be influenced by preprocessor defines. The functioning of your code should always be concise. Any other form of logic (platform, debug) should be abstractable in header files.
This is more a guideline than a strict rule, IMHO.
But I agree that c-syntax based solutions are preferred over preprocessor magic.
The conditional compilation is hard to debug. One has to know all the settings in order to figure out which block of code the program will execute.
I once spent a week debugging a multi-threaded application that used conditional compilation. The problem was that the identifier was not spelled the same. One module used #if FEATURE_1 while the problem area used #if FEATURE1 (Notice the underscore).
I a big proponent of letting the makefile handle the configuration by including the correct libraries or objects. Makes to code more readable. Also, the majority of the code becomes configuration independent and only a few files are configuration dependent.
A reasonable goal but not so great as a strict rule
The advice to try and keep preprocessor conditionals in header files is good, as it allows you to select interfaces conditionally but not litter the code with confusing and ugly preprocessor logic.
However, there is lots and lots and lots of code that looks like the made-up example below, and I don't think there is a clearly better alternative. I think you have cited a reasonable guideline but not a great gold-tablet-commandment.
#if defined(SOME_IOCTL)
case SOME_IOCTL:
...
#endif
#if defined(SOME_OTHER_IOCTL)
case SOME_OTHER_IOCTL:
...
#endif
#if defined(YET_ANOTHER_IOCTL)
case YET_ANOTHER_IOCTL:
...
#endif
CPP is a separate (non-Turing-complete) macro language on top of (usually) C or C++. As such, it's easy to get mixed up between it and the base language, if you're not careful. That's the usual argument against macros instead of e.g. c++ templates, anyway. But #ifdef? Just go try to read someone else's code you've never seen before that has a bunch of ifdefs.
e.g. try reading these Reed-Solomon multiply-a-block-by-a-constant-Galois-value functions:
http://parchive.cvs.sourceforge.net/viewvc/parchive/par2-cmdline/reedsolomon.cpp?revision=1.3&view=markup
If you didn't have the following hint, it will take you a minute to figure out what's going on: There are two versions: one simple, and one with a pre-computed lookup table (LONGMULTIPLY). Even so, have fun tracing the #if BYTE_ORDER == __LITTLE_ENDIAN. I found it a lot easier to read when I rewrote that bit to use a le16_to_cpu function, (whose definition was inside #if clauses) inspired by Linux's byteorder.h stuff.
If you need different low-level behaviour depending on the build, try to encapsulate that in low-level functions that provide consistent behaviour everywhere, instead of putting #if stuff right inside your larger functions.
By all means, favor abstraction over conditional compilation. As anyone who has written portable software can tell you, however, the number of environmental permutations is staggering. Some design discipline can help, but sometimes the choice is between elegance and meeting a schedule. In such cases, a compromise might be necessary.
Consider the situation where you are required to provide fully tested code, with 100% branch coverage etc. Now add in conditional compilation.
Each unique symbol used to control conditional compilation doubles the number of code variants you need to test. So, one symbol - you have two variants. Two symbols, you now have four different ways to compile your code. And so on.
And this only applies for boolean tests such as #ifdef. You can easily imagine the problem if a test is of the form #if VARIABLE == SCALAR_VALUE_FROM_A_RANGE.
If your code will be compiled with different C compilers, and you use compiler-specific features, then you may need to determine which predefined macros are available.
It's true that #if #endif does complicate the reading of the code. However I have seen a lot of real world code that have no issues using this and are still going strong. So there may be better ways to avoid using #if #endif but using them is not that bad if proper care is taken.