www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - [OT] #define

reply Andrew Edwards <edwards.ac gmail.com> writes:
Sorry if this is a stupid question but it eludes me. In the 
following, what is THING? What is SOME_THING?

     #ifndef THING
     #define THING
     #endif

     #ifndef SOME_THING
     #define SOME_THING THING *
     #endif

Is this equivalent to:

     alias thing = void;
     alias someThing = thing*;

Thanks,
Andrew
May 22 2017
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 22 May 2017 at 13:11:15 UTC, Andrew Edwards wrote:
     #ifndef THING
     #define THING
     #endif
This kind of thing is most commonly used in include guards https://en.wikipedia.org/wiki/Include_guard#Use_of_.23include_guards You can usually just strip that out in D, since the module system already just works if imported twice.
     #ifndef SOME_THING
     #define SOME_THING THING *
     #endif

 Is this equivalent to:

     alias thing = void;
     alias someThing = thing*;
I'd have to see that in context though to see why they are doing it... it is probably some kind of platform specific type definitions.
May 22 2017
parent reply Andrew Edwards <edwards.ac gmail.com> writes:
On Monday, 22 May 2017 at 13:15:31 UTC, Adam D. Ruppe wrote:
 On Monday, 22 May 2017 at 13:11:15 UTC, Andrew Edwards wrote:
     #ifndef THING
     #define THING
     #endif
This kind of thing is most commonly used in include guards https://en.wikipedia.org/wiki/Include_guard#Use_of_.23include_guards
Have a basic understanding. In the specific case i'm looking at, they are not used as include guards though.
 You can usually just strip that out in D, since the module 
 system already just works if imported twice.
Makes sense.
     #ifndef SOME_THING
     #define SOME_THING THING *
     #endif

 Is this equivalent to:

     alias thing = void;
     alias someThing = thing*;
I'd have to see that in context though to see why they are doing it... it is probably some kind of platform specific type definitions.
Specific context at the following links: https://github.com/glfw/glfw/blob/66ff4aae89572419bb130c5613798e34d7521fc7/deps/glad/glad.h#L24-L48 https://github.com/glfw/glfw/blob/66ff4aae89572419bb130c5613798e34d7521fc7/deps/glad/glad.h#L57-L81 https://github.com/glfw/glfw/blob/66ff4aae89572419bb130c5613798e34d7521fc7/deps/glad/glad.h#L88-L124 Thanks, Andrew
May 22 2017
parent reply Mike Parker <aldacron gmail.com> writes:
On Monday, 22 May 2017 at 16:37:51 UTC, Andrew Edwards wrote:

 Specific context at the following links:
 https://github.com/glfw/glfw/blob/66ff4aae89572419bb130c5613798e34d7521fc7/deps/glad/glad.h#L24-L48
APIENTRY is typically defined in Windows headers to set the stdcall calling convention (which is where we get extern(Windows) in D) in function declarations. You'll find it all over Win32 API headers. In this case, since OpenGL uses it on Windows, glad is checking if it's defined and, if not, defining it as empty for non-Windows platforms. That way it can be used in the function signatures glad generates on every platform. Generally, any functions in the Windows-specific sections with APIENTRY in their declarations need to be declared in D as extern(Windows). APIENTRY itself can be left out of the D binding.
 https://github.com/glfw/glfw/blob/66ff4aae89572419bb130c5613798e34d7521fc7/deps/glad/glad.h#L57-L81
Again, GLAPI is a Windows-specific thing. A lot of libraries that support compiling to a DLL define something similar on Windows. Function declarations need to be exported when compiling a DLL and imported when compiling programs that use the DLL, so the FOOAPI technique is used to apply the correct attribute to each declaration. On other platforms, FOOAPI is defined as empty. You can safely ignore this one, unless you're planning to do a pure D port (not binding) of the library and intend to compile as a shared lib. It tells you which functions need to be exported from the shared lib to match the C API.
 https://github.com/glfw/glfw/blob/66ff4aae89572419bb130c5613798e34d7521fc7/deps/glad/glad.h#L88-L124
This one is a guard that makes sure that everything in the #ifndef GLEXT_64_TYPES_DEFINED block is only imported once. It's explained in the comment: /* This code block is duplicated in glxext.h, so must be protected */ By defining GLEXT_64_TYPES_DEFINED, if glxext.h after, then it presumably also has a #ifndef GLEXT_64_TYPES_DEFINED block and will not redefine those types. This one can also be ignored on the D side.
May 22 2017
parent reply Andrew Edwards <edwards.ac gmail.com> writes:
On Monday, 22 May 2017 at 16:56:10 UTC, Mike Parker wrote:
 On Monday, 22 May 2017 at 16:37:51 UTC, Andrew Edwards wrote:

 Specific context at the following links:
 https://github.com/glfw/glfw/blob/66ff4aae89572419bb130c5613798e34d7521fc7/deps/glad/glad.h#L24-L48
Generally, any functions in the Windows-specific sections with APIENTRY in their declarations need to be declared in D as extern(Windows). APIENTRY itself can be left out of the D binding.
There isn't any Windows specific section. Every function pointer in the library is decorated in one of the following two forms void (APIENTRY *NAME)(PARAMS) or void (APIENTRYP NAME)(PARAMS) Both happen to be the exact same. So does mean that for every function pointer in the file, I need to duplicate as such? version (Windows) { extern(Windows) { alias NAME = void function(PARAMS); } } else { extern(C) { alias NAME = void function(PARAMS); } }
 https://github.com/glfw/glfw/blob/66ff4aae89572419bb130c5613798e34d7521fc7/deps/glad/glad.h#L57-L81
Again, GLAPI is a Windows-specific thing. [...] You can safely ignore this one, unless you're planning to do a pure D port (not binding) of the library and intend to compile as a shared lib. It tells you which functions need to be exported from the shared lib to match the C API.
So if I'm understanding correctly, on Windows platforms this: typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); GLAPI PFNGLDISABLEPROC glad_glDisable; #define glDisable glad_glDisable is technically: typedef void (__syscall* PFNGLDISABLEPROC)(GLenum cap); extern "C" PFNGLDISABLEPROC glad_glDisable; #define glDisable glad_glDisable which in D is: // extern (Windows) obviated by the fact that the following line exports to the C API? extern (C) alias glad_glDisable = void function(GLenum cap); glad_glDisable glDisable;
 https://github.com/glfw/glfw/blob/66ff4aae89572419bb130c5613798e34d7521fc7/deps/glad/glad.h#L88-L124
[...] This one can also be ignored on the D side.
Got it.
May 22 2017
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 22 May 2017 at 18:44:10 UTC, Andrew Edwards wrote:
 Both happen to be the exact same. So does mean that for every 
 function pointer in the file, I need to duplicate as such?
You can use `extern(System)` or that case in D. It will be extern(Windows) on win an extern(C) elsewhere - just like what the C is doing.
May 22 2017
parent Andrew Edwards <edwards.ac gmail.com> writes:
On Monday, 22 May 2017 at 18:48:44 UTC, Adam D. Ruppe wrote:
 On Monday, 22 May 2017 at 18:44:10 UTC, Andrew Edwards wrote:
 Both happen to be the exact same. So does mean that for every 
 function pointer in the file, I need to duplicate as such?
You can use `extern(System)` or that case in D. It will be extern(Windows) on win an extern(C) elsewhere - just like what the C is doing.
Okay... got it. Thanks.
May 22 2017
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Monday, 22 May 2017 at 18:44:10 UTC, Andrew Edwards wrote:
 There isn't any Windows specific section. Every function 
 pointer in the library is decorated in one of the following two 
 forms

     void (APIENTRY *NAME)(PARAMS)

 or

     void (APIENTRYP NAME)(PARAMS)
Sorry, I worded that poorly. APIENTRY is defined somewhere in the Win32 headers. IIRC, it's an alias for WINAPI, which is also defined in the Win32 headers to declare the standard call calling convention (which is __stdcall on the MS compiler and something else, I think, on GCC). OpenGL includes windows.h on Windows, so the Win32-specific stuff is there. The functions aren't in any Win32-specific sections.
 Both happen to be the exact same. So does mean that for every 
 function pointer in the file, I need to duplicate as such?

 version (Windows)
 {
     extern(Windows)
     {
         alias NAME = void function(PARAMS);
     }
 }
 else
 {
     extern(C)
     {
         alias NAME = void function(PARAMS);
     }
 }
Adam's answer about extern(System) is the solution. Before it was added, this code is exactly what I had to use in Derelict.
 So if I'm understanding correctly, on Windows platforms this:

     typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap);
     GLAPI PFNGLDISABLEPROC glad_glDisable;
     #define glDisable glad_glDisable

 is technically:

     typedef void (__syscall* PFNGLDISABLEPROC)(GLenum cap);
     extern "C" PFNGLDISABLEPROC glad_glDisable;
     #define glDisable glad_glDisable
__stdcall, not __syscall
 which in D is:

     // extern (Windows) obviated by the fact that the following 
 line exports to the C API?
     extern (C) alias glad_glDisable = void function(GLenum cap);
     glad_glDisable glDisable;
extern(System) for anything cross-platform. If it's something you're using only on Windows, then you can use extern(Windows).
May 22 2017
parent Andrew Edwards <edwards.ac gmail.com> writes:
On Tuesday, 23 May 2017 at 00:14:43 UTC, Mike Parker wrote:
 On Monday, 22 May 2017 at 18:44:10 UTC, Andrew Edwards wrote:
 There isn't any Windows specific section. Every function 
 pointer in the library is decorated in one of the following 
 two forms

     void (APIENTRY *NAME)(PARAMS)

 or

     void (APIENTRYP NAME)(PARAMS)
Sorry, I worded that poorly. APIENTRY is defined somewhere in the Win32 headers. IIRC, it's an alias for WINAPI, which is also defined in the Win32 headers to declare the standard call calling convention (which is __stdcall on the MS compiler and something else, I think, on GCC). OpenGL includes windows.h on Windows, so the Win32-specific stuff is there. The functions aren't in any Win32-specific sections.
[....] Much appreciated Mike and everyone else. I was able to make a good deal of progress today because of your input. Andrew
May 23 2017
prev sibling next sibling parent reply Eugene Wissner <belka caraus.de> writes:
On Monday, 22 May 2017 at 13:11:15 UTC, Andrew Edwards wrote:
 Sorry if this is a stupid question but it eludes me. In the 
 following, what is THING? What is SOME_THING?

     #ifndef THING
     #define THING
     #endif

     #ifndef SOME_THING
     #define SOME_THING THING *
     #endif

 Is this equivalent to:

     alias thing = void;
     alias someThing = thing*;

 Thanks,
 Andrew
No, it isn't. THING is empty. Some SOME_THING is "*". Emtpy macros are used for example to inline the functions: #ifndef MY_INLINE #define MY_INLINE #endif MY_INLINE void function() { } So you can choose at compile time if you want inline the function or not. D is here more restrictive than C, I don't know a way to port to D.
May 22 2017
parent Andrew Edwards <edwards.ac gmail.com> writes:
On Monday, 22 May 2017 at 13:18:51 UTC, Eugene Wissner wrote:
 On Monday, 22 May 2017 at 13:11:15 UTC, Andrew Edwards wrote:
 Sorry if this is a stupid question but it eludes me. In the 
 following, what is THING? What is SOME_THING?

     #ifndef THING
     #define THING
     #endif

     #ifndef SOME_THING
     #define SOME_THING THING *
     #endif

 Is this equivalent to:

     alias thing = void;
     alias someThing = thing*;

 Thanks,
 Andrew
No, it isn't. THING is empty. Some SOME_THING is "*". Emtpy macros are used for example to inline the functions: #ifndef MY_INLINE #define MY_INLINE #endif MY_INLINE void function() { } So you can choose at compile time if you want inline the function or not. D is here more restrictive than C, I don't know a way to port to D.
Thanks Eugene, got it. For context, see response to Adam.
May 22 2017
prev sibling next sibling parent reply Dukc <ajieskola gmail.com> writes:
On Monday, 22 May 2017 at 13:11:15 UTC, Andrew Edwards wrote:
 Sorry if this is a stupid question but it eludes me. In the 
 following, what is THING? What is SOME_THING?

     #ifndef THING
     #define THING
     #endif

     #ifndef SOME_THING
     #define SOME_THING THING *
     #endif

 Is this equivalent to:

     alias thing = void;
     alias someThing = thing*;

 Thanks,
 Andrew
I assume you know that the above part is c/c++ preprocessor, which is not normally used at d? THING is nothing there. If you use it at code, I'm not sure how it behaves. Either it does not compile at all, or it behaves as nothing (think whitespace). If it's the latter, SOME_THING would be a lone asterix. Can be used as operator both unarily and binarily. #IFNDEF regonizes all preprocessor declarations, empty or not. The closest D equivalent to #DEFINE is a string mixin. The equivalent to above is: static if (!is(typeof(thing))) enum thing = ""; static if (!is(typeof(someThing))) enum someThing = thing ~ " *"; This is used differently than a preprocessor though. Instead of: safe void main() { import std.stdio; writeln(5 SOMETHING 6); } ...you have to explicitly mix the text in: safe void main() { import std.stdio; mixin("writeln(5 " ~ someThing ~ " 6);"); //30 } Because just mixing in text straight away is generally quite an ugly solution, so is the syntax. In most cases you would want to replace it with a more context-specific solution: -If the symbol is a literal, an enum literal OF THE TYPE OF THE LITERAL is preferred. -If the symbol is an empty declaration used only for #IFNDEFS, version statements are a cood canditate for replacing it. Perhaps that's what you're looking for? -If the symbol is a type, or a name of another global symbol, alias is the way to go. -In the case of function-type #DEFINES, eponymous templates or aliases to lambdas are your best bets. Note, there is no equivalent to #UNDEF in D. But unlike the preprocessor, all D symbols cease to exist when their scope ends, and in almost all cases that's a much better thing!
May 22 2017
parent Andrew Edwards <edwards.ac gmail.com> writes:
On Monday, 22 May 2017 at 13:52:35 UTC, Dukc wrote:
 On Monday, 22 May 2017 at 13:11:15 UTC, Andrew Edwards wrote:
 Sorry if this is a stupid question but it eludes me. In the 
 following, what is THING? What is SOME_THING?
[...] I assume you know that the above part is c/c++ preprocessor, which is not normally used at d?
Yes, I am aware.
 THING is nothing there. If you use it at code, I'm not sure how 
 it behaves. Either it does not compile at all, or it behaves as 
 nothing (think whitespace). If it's the latter, SOME_THING 
 would be a lone asterix. Can be used as operator both unarily 
 and binarily. #IFNDEF regonizes all preprocessor declarations, 
 empty or not.

 The closest D equivalent to #DEFINE is a string mixin. The 
 equivalent to above is:
 static if (!is(typeof(thing))) enum thing = "";
 static if (!is(typeof(someThing))) enum someThing = thing ~ " 
 *";
[...]

 ...you have to explicitly mix the text in:

  safe void main()
 {   import std.stdio;
     mixin("writeln(5 " ~ someThing ~ " 6);"); //30
 }
That's really ugly... Hope I'll never have to resort to that. The specific idiom does have it's uses though, as in the case of self-important lookups.
 [...]

 -If the symbol is an empty declaration used only for #IFNDEFS, 
 version statements are a cood canditate for replacing it. 
 Perhaps that's what you're looking for?
Not exactly but I get the point. This list is golden, thanks for the assist. Andrew
May 22 2017
prev sibling parent biocyberman <biocyberman gmail.com> writes:
On Monday, 22 May 2017 at 13:11:15 UTC, Andrew Edwards wrote:
 Sorry if this is a stupid question but it eludes me. In the 
 following, what is THING? What is SOME_THING?

     #ifndef THING
     #define THING
     #endif

     #ifndef SOME_THING
     #define SOME_THING THING *
     #endif

 Is this equivalent to:

     alias thing = void;
     alias someThing = thing*;

 Thanks,
 Andrew
Hi Andrew This is why need to learn more about C and C++ when I want to port them to D. You can get a bit of reading about C preprocessor here: https://www.tutorialspoint.com/cprogramming/c_preprocessors.htm Regarding your question: I've been porting some C code with macros, they can be translated into D as aliases, functions, structs, templates, mixins etc. So maybe an excerpt from the real code would be more straight forward.
May 22 2017