Jump to page: 1 2
Thread overview
[OT] #define
May 22, 2017
Andrew Edwards
May 22, 2017
Adam D. Ruppe
May 22, 2017
Andrew Edwards
May 22, 2017
Mike Parker
May 22, 2017
Andrew Edwards
May 22, 2017
Adam D. Ruppe
May 23, 2017
Andrew Edwards
May 23, 2017
Mike Parker
May 23, 2017
Andrew Edwards
May 22, 2017
Eugene Wissner
May 22, 2017
Andrew Edwards
May 22, 2017
Dukc
May 22, 2017
Andrew Edwards
May 22, 2017
biocyberman
May 22, 2017
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
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
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
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
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
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
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
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
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
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.

« First   ‹ Prev
1 2