I'm working on existing C++ code, which is using a kind of API.
While browsing the code I found a strange syntax that I saw now for the first time and I can't figure out what it does or how such is called.
It goes like this:
class KINDA_API foobar : public foo {
// Some class declarations
};
Everything after foobar is understandable for me. But what means that KINDA_API? What does this do? Is that any kind of advanced derivation or something like that?
Maybe there is any other Thread that answers this, and I also searched for it, but I don't even know how this is called ^^'
Usually when you see OMGWFT_API declarations in this exact way, this is a 'magic switch' for building a library in correct "mode":
static linking - OMGWFT_API replaced by "" (empty string)
dynamic linking - DLL - OMGWFT_API replaced by declspec(dllexport)
dynamic linking - EXE - OMGWFT_API replaced by declspec(dllimport)
i.e.
#ifdef BUILD_ME_AS_STATICLIB
#define OMGWFT_API
#else
#ifdef BUILD_ME_AS_DLL
#define OMGWFT_API declspec(dllexport)
#else
#define OMGWFT_API declspec(dllimport)
#endif
#endif
This is of course just an sketch of example, but I think you get the point now. Keywords are taken from MSVC not GCC< because I accidentially happen to remember them.
The "BUILD_ME_AS...." macros would be then defined via project options or -D command line switch.
However, it the OMGWFT_API can be set to have any meaning, so be sure to grep/search for a #define that sets this.
I guess it is a #define-d macro that does some "magic" before compile.
If you look through the existing call you are likely to find somthing like:
#ifdef _WIN32
#define KINDA_API <windows specific attribute>
#elif __linux
#define KINDA_API <linux specific attribute>
etc...
These macros are more likely conditioned on compilers and/or their versions rather than operating system but you get the idea...
Related
So I have multiple levels of #include going on, which eventually looks something like this:
MyHeader.h:
...
#include WindowsPlatform.h
...
void MyFunc()
{
printf("File path max length: %d", PLATFORM_MAX_FILEPATH_LENGTH);
return;
}
WindowsPlatform.h
#include minwindef.h
...
#define PLATFORM_MAX_FILEPATH_LENGTH MAX_PATH
...
minwindef.h
...
#define MAX_PATH 260
...
Note that I don't control these headers except my own.
I'm trying to override the MAX_PATH definition, apparently through a command-line parameter that looks like -DMAX_PATH=1024 (It's part of the automated build tool thing).
However, it seems that stuff I put there isn't overriding the #define in the file. :/
What am I doing wrong?
The best fix is probably to modify the header file. Try:
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
If that doesn't work, something more extreme is needed, like:
#ifdef OVERRIDE_MAX_PATH
#define MAX_PATH OVERRIDE_MAX_PATH
#else
#define MAX_PATH 260
#endif
And use -DOVERRIDE_MAX_PATH=1024.
Both C and C++ language specifications are deliberately designed to quietly allow "matching" macro redefinitions and complain about conflicting macro redefinitions. In both C and C++ conflicting macro definitions are "errors" (ill-formed, constraint violations - choose your term). Which means that your attempts to redefine a macro to a different value will normally trigger diagnostic messages.
If your compiler does not complain, then either your conflicting definitions never meet each other or you are doing something else incorrectly. In any case, it won't work that way.
It looks like you try to write some OS-independent code. If I understand correctly and WindowsPlatform.h is Windows-specific (so you already have an abstraction layer) - why you bother with overriding anything?
Why do you do this:
#define PLATFORM_MAX_FILEPATH_LENGTH MAX_PATH
and try do mess with standard definitions? Why not this way:
#define PLATFORM_MAX_FILEPATH_LENGTH 1024
If your PLATFORM_MAX_FILEPATH_LENGTH is defined in platform-dependent header, you can define its value differently for each platform. If you always want it to be 1024, just define it in some common header.
Currently, I do not see any reason to do what you are trying to do. It is incorret anyway - you should not mess with predefined, library-wide macros, because libraries are compiled using these defined values - you can get yourself some serious trouble this way!
typically #define would be used to define a constant or a macro. However it is valid code to use #define in the following way.
#define MAX // does this do anything?
#define MAX 10 // I know how to treat this.
So, if I #define MAX 10, I know my pre-processor replaces all instances of MAX with 10. If someone uses #define MAX by itself however with no following replacement value, it's valid. Does this actually DO anything?
My reason for asking is that I am writing a compiler for c in c++ and handling preprocessor directives is required but I haven't been able to find out if there is any functionality I need to have when this occurs or if I just ignore this once my preprocess is done.
My first instinct is that this will create a symbol in my symbol table with no value named MAX, but it is equally possible it will do nothing.
As an add in question which is kind of bad form I know, but I'm really curious. Are there situations in real code where something like this would be used?
Thanks,
Binx
A typical example are header guards:
#ifndef MYHEADER
#define MYHEADER
...
#endif
You can test if something is defined with #ifdef / ifndef.
It creates a symbol with a blank definition, which can later be used in other preprocessor operations. There are a few things it can be used for:
1) Branching.
Consider the following:
#define ARBITRARY_SYMBOL
// ...
#ifdef ARBITRARY_SYMBOL
someCode();
#else /* ARBITRARY_SYMBOL */
someOtherCode();
#endif /* ARBITRARY_SYMBOL */
The existence of a symbol can be used to branch, selectively choosing the proper code for the situation. A good use of this is handling platform-specific equivalent code:
#if defined(_WIN32) || defined(_WIN64)
windowsCode();
#elif defined(__unix__)
unixCode();
#endif /* platform branching */
This can also be used to dummy code out, based on the situation. For example, if you want to have a function that only exists while debugging, you might have something like this:
#ifdef DEBUG
return_type function(parameter_list) {
function_body;
}
#endif /* DEBUG */
1A) Header guards.
Building on the above, header guards are a means of dummying out an entire header if it's already included in a project that spans multiple source files.
#ifndef HEADER_GUARD
#define HEADER_GUARD
// Header...
#endif /* HEADER_GUARD */
2) Dummying out a symbol.
You can also use defines with blank definitions to dummy out a symbol, when combined with branching. Consider the following:
#ifdef _WIN32
#define STDCALL __stdcall
#define CDECL __cdecl
// etc.
#elif defined(__unix__)
#define STDCALL
#define CDECL
#endif /* platform-specific */
// ...
void CDECL cdeclFunc(int, int, char, const std::string&, bool);
// Compiles as void __cdecl cdeclFunc(/* args */) on Windows.
// Compiles as void cdeclFunc(/* args */) on *nix.
Doing something like this allows you to write platform-independent code, but with the ability to specify the calling convention on Windows platforms. [Note that the header windef.h does this, defining CDECL, PASCAL, and WINAPI as blank symbols on platforms that don't support them.] This can also be used in other situations, whenever you need a preprocessor symbol to only expand to something else under certain conditions.
3) Documentation.
Blank macros can also be used to document code, since the preprocessor can strip them out. Microsoft is fond of this approach, using it in windef.h for the IN and OUT symbols often seen in Windows function prototypes.
There are likely other uses as well, but those are the only ones I can think of off the top of my head.
It doesn't "do" anything in the sense that it will not add anything to a line of code
#define MAX
int x = 1 + 2; MAX // here MAX does nothing
but what an empty define does is allow you to conditionally do certain things like
#ifdef DEBUG
// do thing
#endif
Similarly header guards use the existance of a macro to indicate if a file has already been included in a translation unit or not.
The C Preprocessor (CPP) creates a definitions table for all variables defined with the #define macro. As the CPP passes through the code, it does at least two things with this information.
First, it does a token replacement for the defined macro.
#define MAX(a,b) (a > b) ? (a) : (b)
MAX(1,2); // becomes (1 > 2) ? (1) : (2);
Second, it allows for those definitions to be searched for with other preprocessor macros such as #ifdef, #ifndef, #undef, or CPP extensions like #if defined(MACRO_NAME).
This allows for flexibility in using macro definitions in those cases when the value is not important, but the fact that a token is defined is important.
This allows for code like the following:
// DEBUG is never defined, so this code would
// get excluded when it reaches the compiler.
#ifdef DEBUG
// ... debug printing statements
#endif
#define does a character-for-character replacement. If you give no value, then the identifier is replaced by...nothing. Now this may seem strange. We often use this just to create an identifier whose existence can be checked with #ifdef or #ifndef. The most common use is in what are called "inclusion guards".
In your own preprocessor implementation, I see no reason to treat this as a special case. The behavior is the same as any other #define statement:
Add a symbol/value pair to the symbol table.
Whenever there is an occurrence of the symbol, replace it with its value.
Most likely, step 2 will never occur for a symbol with no value. However, if it does, the symbol is simply removed since its value is empty.
According to cplusplus.com, the syntax to define a macro is:
#define identifier replacement
However, I sometimes stumble upon a macro definition which doesn't contain a replacement. For example in afxwin.h, there is the following preprocessor definition:
#define afx_msg // intentional placeholder
My questions:
What happens at compile-time when a preprocessor definition that doesn't have a replacement is used? Is it simply ignored? For example, does the line afx_msg void OnAddButton(); become void OnAddButton();?
What is the purpose of using preprocessor without replacement? Is it simply to make code more clear?
"Nothing" (no text) is a valid replacement text for a macro. It will simply be removed (more precisely, replaced by nothing) by the preprocessor.
There are multiple reasons why you'd use something like this. One is to simply use the macro in #ifdef and similar constructrs.
Another is conditional compilation. A typical use case is public APIs and DLL exports. On Windows, you need to mark a function as exported from a DLL (when building the DLL) or as imported from a DLL (when linking against the DLL). On ELF systems, no such declarations are necessary. Therefore, you'll often see code like this in public library headers:
#ifdef _WIN32
#ifdef BUILDING_MYLIB
#define MYLIB_API __declspec(dllexport)
#else
#define MYLIB_API __declspec(dllimport)
#endif
#else
#define MYLIB_API
#endif
void MYLIB_API myApiFunction();
Yet another reason could be code processing tools. Perhaps you have a tool which parses source code, extracting a list of functions with a certain marker. You can define such a marker as an empty macro.
#define bla
simply defines bla.
you can use it with
#ifdef bla
...
place some code here
...
#endif
a typical use case is #define DEBUG to enable special code parts in debugging mode.
Another way to set such things from "outside" is:
g++ -DDEBUG x.cpp
which also sets the macro DEBUG defined.
And every header file should have something like:
#ifndef THIS_HEADER_INCLUDE_GUARD
#define THIS_HEADER_INCLUDE_GUARD
...
rest of header file
...
#endif
This simply protects your header file for (recursivly) read more the once.
Some can be done with implementation specific #pragma once.
the preprocessor processes it, removing it and replacing it with nothing
could be a variety of reasons, including readability, portability, custom compiler features, etc.
I recently came across this sort of code in someone's opengl shader class and am not sure of its use.
As I understand it from reading IBM's documentation, the #define ONEWORD will remove any occurence of ONEWORD in the subsequent text.
What is the purpose of having ONEWORD in this code at all if all occurrences are removed? What does having a token like that, after a class keyword but before a class name, really mean?
I've only used #define for include guards in the past so this is entirely new for me.
#define ONEWORD
class ONEWORD FooClass
{
FooClass();
~FooClass();
};
The code I saw this in is here: https://dl.dropbox.com/u/104992465/glsl.h
Just in case I've made its context too abstract.
It's to allow you to easily add compiler specific keywords to your class declaration. For instance with Visual Studio, if you wanted to put this class in a DLL, you would change your definition to
#define ONEWORD __declspec( dllexport )
See here for another example
Oh, so after looking at the actual code, it's not ONEWORD, but rather GLSAPI. These XYZ_API macros are often used for conditionally specifying platform-specific linkage, such as some __attributes__ which require different treatment on, for example, Windows and Unixes. So you can expect GLSAPI to be defined in one of the header files (maybe in config.h) like this:
#ifdef WIN32
# define GLSAPI __dllimport
#elif defined __linux__
# define GLSAPI __attribute__((visibility("visible")))
#else
# define GLSAPI
#endif
(Pseudo-code, I'm not sure about all the attributes and linkage "qualifiers", but you can look them up in the code.)
Here's a little problem I've been thinking about for a while now that I have not found a solution for yet.
So, to start with, I have this function guard that I use for debugging purpose:
class FuncGuard
{
public:
FuncGuard(const TCHAR* funcsig, const TCHAR* funcname, const TCHAR* file, int line);
~FuncGuard();
// ...
};
#ifdef _DEBUG
#define func_guard() FuncGuard __func_guard__( TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), __LINE__)
#else
#define func_guard() void(0)
#endif
The guard is intended to help trace the path the code takes at runtime by printing some information to the debug console. It is intended to be used such as:
void TestGuardFuncWithCommentOne()
{
func_guard();
}
void TestGuardFuncWithCommentTwo()
{
func_guard();
// ...
TestGuardFuncWithCommentOne();
}
And it gives this as a result:
..\tests\testDebug.cpp(121):
Entering[ void __cdecl TestGuardFuncWithCommentTwo(void) ]
..\tests\testDebug.cpp(114):
Entering[ void __cdecl TestGuardFuncWithCommentOne(void) ]
Leaving[ TestGuardFuncWithCommentOne ]
Leaving[ TestGuardFuncWithCommentTwo ]
Now, one thing that I quickly realized is that it's a pain to add and remove the guards from the function calls. It's also unthinkable to leave them there permanently as they are because it drains CPU cycles for no good reasons and it can quickly bring the app to a crawl. Also, even if there were no impacts on the performances of the app in debug, there would soon be a flood of information in the debug console that would render the use of this debug tool useless.
So, I thought it could be a good idea to enable and disable them on a per-file basis.
The idea would be to have all the function guards disabled by default, but they could be enabled automagically in a whole file simply by adding a line such as
EnableFuncGuards();
at the top of the file.
I've thought about many a solutions for this. I won't go into details here since my question is already long enough, but let just say that I've tried more than a few trick involving macros that all failed, and one involving explicit implementation of templates but so far, none of them can get me the actual result I'm looking for.
Another restricting factor to note: The header in which the function guard mechanism is currently implemented is included through a precompiled header. I know it complicates things, but if someone could come up with a solution that could work in this situation, that would be awesome. If not, well, I certainly can extract that header fro the precompiled header.
Thanks a bunch in advance!
Add a bool to FuncGuard that controls whether it should display anything.
#ifdef NDEBUG
#define SCOPE_TRACE(CAT)
#else
extern bool const func_guard_alloc;
extern bool const func_guard_other;
#define SCOPE_TRACE(CAT) \
NppDebug::FuncGuard npp_func_guard_##__LINE__( \
TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), \
__LINE__, func_guard_##CAT)
#endif
Implementation file:
void example_alloc() {
SCOPE_TRACE(alloc);
}
void other_example() {
SCOPE_TRACE(other);
}
This:
uses specific categories (including one per file if you like)
allows multiple uses in one function, one per category or logical scope (by including the line number in the variable name)
compiles away to nothing in NDEBUG builds (NDEBUG is the standard I'm-not-debugging macro)
You will need a single project-wide file containing definitions of your category bools, changing this 'settings' file does not require recompiling any of the rest of your program (just linking), so you can get back to work. (Which means it will also work just fine with precompiled headers.)
Further improvement involves telling the FuncGuard about the category, so it can even log to multiple locations. Have fun!
You could do something similar to the assert() macro where having some macro defined or not changes the definition of assert() (NDEBUG in assert()'s case).
Something like the following (untested):
#undef func_guard
#ifdef USE_FUNC_GUARD
#define func_guard() NppDebug::FuncGuard __npp_func_guard__( TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), __LINE__)
#else
#define func_guard() void(0)
#endif
One thing to remember is that the include file that does this can't have include guard macros (at least not around this part).
Then you can use it like so to get tracing controlled even within a compilation unit:
#define USE_FUNC_GUARD
#include "funcguard.h"
// stuff you want traced
#undef USE_FUNC_GUARD
#include "funcguard.h"
// and stuff you don't want traced
Of course this doesn't play 100% well with pre-compiled headers, but I think that subsequent includes of the header after the pre-compiled stuff will still work correctly. Even so, this is probably the kind of thing that shouldn't be in a pre-compiled header set.