2

I am trying to make sense of the libspatialindex source code. Being new to c++, I have difficulty wrapping my head around the concept of macros. The library’s API wrapper for C, sidx_api.cc, directly and indirectly includes numerous headers two of which seemingly define the same macro, concerned with interfacing a dynamic library, without ‘undef’:

Tools.h

45 #if (defined _WIN32 || defined _WIN64 || defined WIN32 || defined WIN64) && !defined __GNUC__
46  #ifdef SIDX_DLL_EXPORT
47  #define SIDX_DLL __declspec(dllexport)
48  #else
49  #define SIDX_DLL __declspec(dllimport)
50  #endif
51 
52  // Nuke this annoying warning. See http://www.unknownroad.com/rtfm/VisualStudio/warningC4251.html
53 #pragma warning( disable: 4251 )
54 
55 #else
56  #define SIDX_DLL
57 #endif

sidx_export.h

29 #pragma once
30 
31 #ifndef SIDX_C_DLL  
32 #if defined(_MSC_VER)
33 # define SIDX_C_DLL __declspec(dllexport)
34 # define SIDX_DLL __declspec(dllexport)
35 #else
36 # if defined(USE_GCC_VISIBILITY_FLAG)
37 # define SIDX_C_DLL __attribute__ ((visibility("default")))
38 # define SIDX_DLL __attribute__ ((visibility("default")))
39 # else
40 # define SIDX_C_DLL
41 # define SIDX_DLL
42 # endif
43 #endif
44 #endif

I believe that redefining a macro without ‘undef’ is problematic, e.g., as discussed here and here. Am I missing something here? Thanks.

Amis71
  • 33
  • 6
  • You'll generally get warnings when redefining macros. Do you? – Quentin Jun 11 '19 at 08:32
  • 4
    The macros you show are defined only *once* because of the conditions. – Some programmer dude Jun 11 '19 at 08:32
  • @ Some programmer dude You man that sidx_dll_export in line 46 will always be defined? – Amis71 Jun 11 '19 at 08:36
  • Consider emailing the person who put their email at the top of the file? Does it build? Does it work? The various `if defined` around these might stop redefinitions. At a high level the `dllexport` is for functions to be exported for use outside a dll/so which happens differently on *nix and Windows. How are you building it? For which platform? – doctorlove Jun 11 '19 at 08:37
  • 1
    If I paste this into MSVC, then `SIDX_DLL` is indeed defined twice, once as `__declspec(dllimport)` and once as `__declspec(dllexport)`. Yikes! – Blaze Jun 11 '19 at 08:38
  • What's missing from this is what macros are defined in the project settings when building the source files that include the header files. – Some programmer dude Jun 11 '19 at 08:40
  • @doctorlove That is the problem, I mainly work with python and do not have to worry about macros. To speed up rtree query in python, I decided to wrap libspatialindex using ctypes. It has been only a week since I have started reading up on c++ syntax. I have not run this code and just wanted to understand its various parts. – Amis71 Jun 11 '19 at 08:41
  • Check it builds first. Then maybe try to write a dll/so yourself to understand some of it. Again at a high level some of these are for *nix and others for Windows – doctorlove Jun 11 '19 at 08:44
  • @doctorlove Well, I guess that is a good option that I have to take sooner or later. – Amis71 Jun 11 '19 at 08:52
  • @Someprogrammerdude How can I find out about the macros that are built during compilation and build? – Amis71 Jun 11 '19 at 08:52
  • Check makefiles and Visual Studio project files (whichever is relevant). – Some programmer dude Jun 11 '19 at 09:01
  • @Blaze I don't see how that can happen. Only one of those `#define` lines is executed, depending on `#ifdef DIX_DLL_EXPORT`. – Barmar Jun 11 '19 at 09:12
  • @Barmar it happens if one of those `WIN` macros is defined, `__GNUC__` is not defined, `SIDX_DLL_EXPORT` is not defined and `SIDX_C_DLL` isn't defined either. – Blaze Jun 11 '19 at 09:14
  • I see, it's getting defined in `Tools.h` and then getting redefined in `sidx_export.h`. – Barmar Jun 11 '19 at 09:23
  • @Blaze you are not supposed to just paste it and hope it will work. You need a complete environment of a project with its settings and compilation flags. – n. m. could be an AI Jun 11 '19 at 09:30

2 Answers2

3

No macro is illegally redefined here. Some may be defined more than once with identical definitions, which is OK. It's non-identical definitions that constitute a problem.

The DLL itself is always built with SIDX_DLL_EXPORT defined by the project settings. Code that uses the DLL is built without this macro being defined.

The second header is a part of the DLL. It is always compiled with SIDX_DLL_EXPORT being defined. Thus the macros defined by it, if any, are always identical to those defined in the first header. Such identical redefinition does not constitute a problem.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
2

If you redefine it you need to redefine it using exactly the same list of preprocessing tokens. This is true for function-macros and for object-macros.

From 6.10.3 Macroreplacement p2:

An identifier currently defined as an object-like macro shall not be redefined by another #define preprocessing directive unless the second definition is an object-like macro definition and the two replacement lists are identical.

Likewise, an identifier currently defined as a function-like macro shall not be redefined by another #define preprocessing directive unless the second definition is a function-like macro definition that has the same number and spelling of parameters, and the two replacement lists are identical.

So this definitions use shall.

Now, from 4.Conformance p2:

If a ‘‘shall’’or‘‘shall not’’requirement that appears outside of a constraint is violated, the behavior is undefined.

This is the official definition. So, without dropping the macro symbol out from the environment of the preprocessor (using #undef) before you redefine it you get undefined behavior.

In case you find other situation in some implementations of C, this is not standardized.

Correctly it would be to insert different definitions in function of some condition that you set outside:

#if COND
#define M M1
#else
#define M M2
#endif

If you use some library that redefines it, for sure there are some macros that set the COND and make the things well defined. You need to learn how to use the library. Redefining it with different list of pp tokens is not valid.

Community
  • 1
  • 1
alinsoar
  • 15,386
  • 4
  • 57
  • 74
  • The link given is to a draft of C99, which is obsolete. The same provisions are also expressed by the two subsequent versions of the Standard, however. – John Bollinger Jun 11 '19 at 12:07