-1
#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
// How to determine the identifier above?  
// Where did `MATHLIBRARY_API` came from?
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif

Another example:

#ifdef BUILD_DLL
    // same question here.where BUILD_DLL came from?
    #define DLL_EXPORT __declspec(dllexport)     
#else
    #define DLL_EXPORT __declspec(dllimport)
#endif

I'm working on making a header file for a DLL, and I'm really stuck on this. I'm confused about what identifier I should use after #ifdef or #ifndef directives.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
alireza m
  • 9
  • 3
  • It came from literally right there. `#define MATHLIBRARY_API __declspec(dllimport)` defines `MATHLIBRARY_API`, an instruction to the preprocessor that it must replace the `MATHLIBRARY_API` token with `__declspec(dllimport)` anywhere the preprocessor finds it after the definition. – user4581301 Aug 01 '23 at 20:10
  • you first ask for `MATHLIBRARY_API` which is `#define`d in your code but then you ask for `#ifndef` / `#ifdef`. One is defining the symbol the latter tests if it is defined. – 463035818_is_not_an_ai Aug 01 '23 at 20:18
  • I suspect the first one is actually asking about `MATHLIBRARY_EXPORTS` rather than `MATHLIBRARY_API`. – paxdiablo Aug 01 '23 at 21:00

2 Answers2

2

Asking where MATHLIBRARY_API comes from seems incongruous, as it's defined right there in the code.

I suspect you're actually asking about using MATHLIBRARY_EXPORTS instead, since you later asked about BUILD_DLL (which is also a using case). So I'll base this answer on that.

Definitions typically happen in one of two places:

  1. From #define earlier in the process. You can see that in operation in your code where it defines, for example, DLL_EXPORT.
  2. As a compiler flag such as -D MATHLIBRARY_EXPORTS.

In terms of the actual names you can use, these are identifiers so have to follow certain rules set down in the standard(1).

You are also responsible for managing "collisions" of those names between individual parts of the compilation process (such as your code and third-party code). So, if two header files that you use each had different definitions for TRUE, that could cause issues:

#define TRUE 1
#define TRUE (!0)

As an example of using this (very similar to your MATHLIBRARY_EXPORTS/MATHLIBRARY_API example, I suspect), see the following code:

#ifdef ACCESS_PRIVATE
    # define PRIVATE
#else
    # define PRIVATE static
#endif

void public_function() { /* code goes here */ }
PRIVATE void private_function() { /* code goes here */ }

If you compile that with g++ -c -o file.o file.c, then private_function() will be static, so not visible outside of the current translation unit.

However, if you added -D ACCESS_PRIVATE to the compiler flags, then the function would not be static and you would be able to access it from other code that you link.

This sort of thing is often done for unit tests of otherwise private functions.


(1) For allowable characters in identifiers, see the current iteration of the standard at time of this answer, C++20 5.10 Identifiers (or equivalent section in other iterations).

This is functionally defined as having the first character drawn from the set (C allows for extra implementation-defined characters, C++ apparently does not):

  • Any upper or lower-case letter, [A-Za-z].
  • An underline character _.
  • Any universal character name in predefined ranges (see the standard for full list), such as \U0001f602 being . However, keep in mind certain universal characters (such as combining characters) are disallowed in the first position of an identifier.

That character is then followed by zero or more subsequent characters which are either:

  • Any digit, [0-9].
  • Any character from the "first character" set above, with "first character" restrictions removed.
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1

The #ifdef and #ifndef are passive, they don't create identifiers, they test for the presence of an identifier. If you want to create an identifier, use #define.

In many compilers or preprocessors, they have a table for identifiers. The #ifdef is the same as #if defined, which means that you are testing if an identifier is defined, meaning that it is in the table.

Edit 1: Example - Header guard

To prevent header files from being including multiple times by the same source file, there is a pattern called an include guard:

#ifndef MYFILE_H
#define MYFILE_H
//...
#endif // MYFILE_H

The first line tests if the identifier MYFILE_H is defined. The second line will create the identifier if the identifier is not defined. This results in the content being ignored if the identifer has been defined.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • thank you.but how to determine an identifier for #define?is it like declaring a variable?means we can use the rules of choosing variable names? – alireza m Aug 01 '23 at 20:16
  • In a good C++ reference, it will define an *identifier*. For *simplicity*, the text following a `#define` is usually an identifier, such as `#define RECTANGLE_H`, where `RECTANGLE_H` is the identifier. – Thomas Matthews Aug 01 '23 at 20:28