Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411482 Posts in 69370 Topics- by 58426 Members - Latest Member: shelton786

April 24, 2024, 01:21:40 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Favourite #defines in C/C++
Pages: 1 [2] 3 4
Print
Author Topic: Favourite #defines in C/C++  (Read 5339 times)
nickgravelyn
Guest
« Reply #20 on: April 09, 2015, 07:12:41 AM »

Most code I see has both include guards and #pragma once. Compilers ignore any pragmas they don't support, so an extra one is harmless.

#pragma once is always worth doing because it causes the preprocessor to stop scanning the file immediately. The saved build time can add up in large projects.
While it might be the case, according to Wikipedia at least some compilers already optimized for header guards and thus there isn't much time saving in the compilation:

Quote
Using #pragma once instead of include guards will, for some compilers, improve compilation speed since it is a higher-level mechanism; the compiler itself can compare filenames or inodes without having to invoke the C preprocessor to scan the header for #ifndef and #endif. It is important to note that some compilers such as GCC, Clang, and EDG-based compilers include specific optimizations to recognize and optimize the handling of include guards, and thus little or no speedup benefit is obtained from the use of #pragma once.

So if you're using GCC or Clang you might not see any speedup. If you're using MSVC there might be a speedup. Honestly I wouldn't bother with #pragma once just for the speedup. IMO the reason to use #pragma once is because writing one simple pragma at the top is nicer than three lines of preprocessor instructions wrapping the whole file.
Logged
Layl
Level 3
***

professional jerkface


View Profile WWW
« Reply #21 on: April 09, 2015, 07:13:48 AM »

Using "#pragma once" is probably a safe bet since pretty much every single compiler supports it. It would be nice to have something better though, there was a module system considered for C++11 but they decided not to go with it. Given how messy introducing new language features seems to have gone so far (non-keyword keywords! what!?) I doubt it would have been that nice to use though.
Logged
oahda
Level 10
*****



View Profile
« Reply #22 on: April 09, 2015, 07:29:44 AM »

Does GCC not support it, tho (going by what nick above said)? What about MinGW?

What are some of those non-keyword keywords, Layl?
Logged

Cheesegrater
Level 1
*



View Profile
« Reply #23 on: April 09, 2015, 07:33:27 AM »

GCC (and the GCC packaged in MinGW) supports it.

I doubt you will run into any problems, unless you're into cross compiling for uncommon embedded platforms, oldish UNIX variants, etc.
Logged
Sik
Level 10
*****


View Profile WWW
« Reply #24 on: April 09, 2015, 10:23:51 AM »

No idea if GCC supports #pragma once but it does support a specific optimization: if it has a header guard and it was included before, the file is completely skipped. Note though that you need to make sure absolutely everything is inside the header guard for this to work (not sure if comments and blank lines before the guard count as an exception, but definitely don't do absolutely anything else, and you could just move those comments inside the guard if you want to make 100% sure)

Also don't define MAX and MIN as macros!

Code:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
...
z = MAX(x++, y++); // x and y get incremented twice

And that gets even worse if the arguments passed are function calls instead of just variables! Just use static functions which will most likely get inlined anyway (though in C you may need different functions for each type, due to lack of overloading):

Code:
static int max(int a, int b) { return a > b ? a : b; }
...
z = max(x++, y++); // safe
Logged
oahda
Level 10
*****



View Profile
« Reply #25 on: April 09, 2015, 10:25:54 AM »

BTW, I seem to be pretty lonely in treating preprocessor stuff like #if((n)def) and #endif as regular code and actually indenting what's between them, but I can't stand not doing that, especially when several are nested. Tongue
Logged

Sik
Level 10
*****


View Profile WWW
« Reply #26 on: April 09, 2015, 10:28:16 AM »

Honestly I prefer that too, the problem is that apparently some compilers have trouble with preprocessor statements that are indented (which is why nobody does it for portable code). I don't think that's the case for any of the current major toolchains though.
Logged
nickgravelyn
Guest
« Reply #27 on: April 09, 2015, 10:38:19 AM »

I like indenting like normal code but in the latest Xcode I got a compiler warning at the end of an indented preprocessor line saying there was no newline at the end of the file. But it still seemed to compile fine. So Shrug
Logged
oahda
Level 10
*****



View Profile
« Reply #28 on: April 09, 2015, 10:41:27 AM »

Hm, I'm pretty sure I'm running more or less the latest, and I'm not getting that. :c (and I'm even running -Wall and -Werror)
Logged

Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #29 on: April 09, 2015, 03:15:02 PM »

Does GCC not support it, tho (going by what nick above said)? What about MinGW?

GCC supports #pragma once right now, but there have been serious discussions about removing it.

Quote
What are some of those non-keyword keywords, Layl?

He's probably referring to keywords that aren't reserved words.  A lot of people use these terms interchangably when they actually mean very different things.

Keywords are words that have special meaning to the compiler.
Reserved words are words that the user is prohibited from using as identifiers.

Most C++ keywords are also reserved words.  Some of the new C++11 keywords are not reserved words.  I believe override and final fall into this group, possibly noexcept as well.

Of course, not all reserved words are keywords.  C and C++ both reserve identifiers containing two consecutive underscores, for example.

A more extreme example is Fortran, where I'm pretty sure that none of the keywords are reserved.
Logged



What would John Carmack do?
Sik
Level 10
*****


View Profile WWW
« Reply #30 on: April 09, 2015, 03:47:55 PM »

I like indenting like normal code but in the latest Xcode I got a compiler warning at the end of an indented preprocessor line saying there was no newline at the end of the file. But it still seemed to compile fine. So Shrug
This is another compatibility issue! Modern compilers should be able to cope with this just fine, but there are some toolchains (ancient mostly) that will panic if the last character of a file isn't a newline >_< You may want to disable that warning I guess (or check if you can make the IDE always insert a newline at the end when missing)

Note how it has nothing to do with the preprocessor.

EDIT: oh I see, the preprocessor removed everything in the line from the # onwards and that included whatever newline may have been after that... But yeah don't worry too much about it, at worst just inject an extra blank line =P
Logged
Cheezmeister
Level 3
***



View Profile
« Reply #31 on: April 09, 2015, 03:58:20 PM »

I waited way too long to start using C++0x

To be fair, C++0x waited way too long to exist, and in the meantime a bunch of better alternatives cropped up (depending on problem domain). Still, good ol' fashioned C is still pretty much king of its hill.

Here's a handy lil one:

Code:
#define DEBUGVAR(x) std::cerr << "[" #x "] = " << (x) << '\n'

Logged

෴Me෴ @chzmstr | www.luchenlabs.com ቒMadeቓ RA | Nextris | Chromathud   ᙍMakingᙌCheezus II (Devlog)
Layl
Level 3
***

professional jerkface


View Profile WWW
« Reply #32 on: April 09, 2015, 10:43:32 PM »

Does GCC not support it, tho (going by what nick above said)? What about MinGW?

What are some of those non-keyword keywords, Layl?

GCC didn't support it before 3.4, but does now.
There's a bunch of new things introduced in C++11 that are technically keywords, such as "final" and "noexcept". However they weren't actually made keywords out of fear that this would break existing builds. Unfortunately this adds even more confusion and inconsistencies to C++.
Logged
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #33 on: April 10, 2015, 04:42:39 AM »

There's a bunch of new things introduced in C++11 that are technically keywords, such as "final" and "noexcept". However they weren't actually made keywords out of fear that this would break existing builds. Unfortunately this adds even more confusion and inconsistencies to C++.

Like I mentioned further up, you're confusing keywords and reserved words.  override and final are keywords, but they are not reserved words.  This actually isn't that uncommon of a thing to see in programming languages.

The issue with #pragma once is that there a number of thorny situations for which there is no standard behavior.  Not to mention that a compiler could use #pragma once to mean anything it wanted to, possibly something that has nothing to do with headers.

Consider cases like this:

Code:
#include <dir1/thing.h>
#include <dir2/thing.h>

Or this:

Code:
#include <thing.h>
#include <somelib/thing.h>

If all these headers are guarded with #pragma once, what happens?  How does #pragma once define a file?  By its name?  By its content?  By its location?  What if you include two identical files from different locations?  There is no universal answer to these questions, since #pragma once is non-standard.  Compiler #1 and compiler #2 could handle these cases in totally different ways, and nobody is wrong, since it's a #pragma.

When given the choice between header guards, which have a well defined standard behavior and a #pragma that could literally do anything, I can't understand why anyone would choose the #pragma.
Logged



What would John Carmack do?
nickgravelyn
Guest
« Reply #34 on: April 10, 2015, 07:02:02 AM »

The issue with #pragma once is that there a number of thorny situations for which there is no standard behavior.  Not to mention that a compiler could use #pragma once to mean anything it wanted to, possibly something that has nothing to do with headers.

Consider cases like this:

Code:
#include <dir1/thing.h>
#include <dir2/thing.h>

Or this:

Code:
#include <thing.h>
#include <somelib/thing.h>

If all these headers are guarded with #pragma once, what happens?  How does #pragma once define a file?  By its name?  By its content?  By its location?  What if you include two identical files from different locations?  There is no universal answer to these questions, since #pragma once is non-standard.  Compiler #1 and compiler #2 could handle these cases in totally different ways, and nobody is wrong, since it's a #pragma.

When given the choice between header guards, which have a well defined standard behavior and a #pragma that could literally do anything, I can't understand why anyone would choose the #pragma.
I use #pragma once for a few reasons:

1. It does what I would expect with Clang (from the latest Xcode) and MSVC (from VS2012) which currently are the only two compilers I care about.
2. It saves me from having to come up with a new preprocessor symbol for each header. Yes, I can just use the name but then when I rename the file I feel compelled to rename the preprocessor.
3. I don't have a lingering #endif at the bottom of the file.

I get that it's nonstandard but the fact is that the compilers supporting it right now are doing so in a pretty reliable way so I'm going to take advantage of that to save myself some hassle and typing. I don't care about really old compilers, non-mainstream compilers, or really even new versions of these same compilers. I only need it to build on these compilers so I can make and ship my game. Smiley
Logged
nickgravelyn
Guest
« Reply #35 on: April 10, 2015, 07:05:43 AM »

Also, back to macros, I like using some macros for logging, both to have conditionally compiled logging as well as to automatically include the location:

Code:
#define _POLY_LOG_STRINGIZE_DETAIL(x)   #x
#define _POLY_LOG_STRINGIZE(x)          _POLY_LOG_STRINGIZE_DETAIL(x)
#define _POLY_LOG_LOCATION              __FILE__ ":" _POLY_LOG_STRINGIZE(__LINE__)

// Core macro for logging. Shouldn't be used directly!
#define _POLY_LOG_IMPL(...)             poly_log(_POLY_LOG_LOCATION, __VA_ARGS__)

// POLY_LOG_ALWAYS for output we want even in release builds
#define POLY_LOG_ALWAYS(...)            _POLY_LOG_IMPL(__VA_ARGS__)

// POLY_LOG_DEBUG for output we only want in debug builds
#if DEBUG
    #define POLY_LOG_DEBUG(...)         _POLY_LOG_IMPL(__VA_ARGS__)
#else
    #define POLY_LOG_DEBUG(...)
#endif

void poly_log(char const* location, char const* format, ...);

And yes, I'm being bad by using a leading underscore which is technically reserved for compilers but I'm using a name that is pretty unlikely to be used by a compiler so YOLO.
Logged
RandyGaul
Level 1
*

~~~


View Profile WWW
« Reply #36 on: April 10, 2015, 08:19:27 AM »

Oh I remember some weirder macros for generating repetitive code.

Macros:
Code:
#define ITERATE_0( F )
#define ITERATE_1( F ) F( 1 )
#define ITERATE_2( F ) ITERATE_1( F ) F( 2 )
#define ITERATE_3( F ) ITERATE_2( F ) F( 3 )

#define ITERATE( F, N ) ITERATE_##N( F )

#define LOOP_0( F, N )
#define LOOP_1( F, N ) F( 1 )
#define LOOP_2( F, N ) LOOP_1( F, N ), F( 2 )
#define LOOP_3( F, N ) LOOP_2( F, N ), F( 3 )

#define LOOP( F, N ) LOOP_##N( F, N )

Usage:
Code:
#define PARAMS( N ) \
    int a##N

#define COLLECT_PARAMS( N ) \
    a##N

#define ACCESS_PARAMS( N ) \
    args[N - 1] = N;

#define FUNC( N ) \
    void func( LOOP( PARAMS, N ) ) \
    { \
        int args[] = { \
            LOOP( COLLECT_PARAMS, N ) \
        }; \
    \
        PRINT( ACCESS_PARAMS, N ) \
    }

ITERATE( FUNC, 3 )

Preprocessor output:
Code:
void func( int a1 )
{
    int args[] = {
        a1
    };

    args[1 - 1] = 1;
}

void func( int a1, int a2 )
{
    int args[] = {
        a1,
        a2
    };

    args[1 - 1] = 1;
    args[2 - 1] = 2;
}

void func( int a1, int a2, int a3 )
{
    int args[] = {
        a1,
        a2,
        a3
    };

    args[1 - 1] = 1;
    args[2 - 1] = 2;
    args[3 - 1] = 3;
}
Logged
InfiniteStateMachine
Level 10
*****



View Profile
« Reply #37 on: April 11, 2015, 07:59:40 PM »

yeah pragma once is pretty much supported to the point where it's practically part of the standard. It's a hell of a lot nicer than ifdefs. People can sometimes forget to update the ifdef when working off a template (say a component) and get a build issue. Even more often I've seen a lot of people to forget to change the ending comment. Pragma solves all that and I haven't run into any issues ever where I've managed to break it using similarly named headers or anything like that.

I've also used it on some pretty specialized compilers and haven't had issues. It seems to even work for other general compilers like dmars.

I also just found that there is a pragma for code folding regions in C++! It's called pragma region. I haven't tried it yet but I'm looking forward to giving it a shot.
Logged

Boreal
Level 6
*


Reinventing the wheel


View Profile
« Reply #38 on: April 12, 2015, 02:57:29 AM »

Ever since constexpr came about I haven't really found any need for macros, since templates already cover code generation.  The only time I use #define anymore is for exporting symbols, since on Windows you need __declspec(dllexport), but nothing on other platforms.
Logged

"In software, the only numbers of significance are 0, 1, and N." - Josh Barczak

magma - Reconstructed Mantle API
oahda
Level 10
*****



View Profile
« Reply #39 on: April 12, 2015, 03:03:09 AM »

I use indentation instead of end comments. Cool

And I never forget changing the header guard when creating or renaming a class. That's the first thing I do always.

Why would one have an end comment in simple header guards anyway unless there's a lot of other preprocessor stuff there? What confusion would one even be trying to avoid? Seems excessive in most cases.
Logged

Pages: 1 [2] 3 4
Print
Jump to:  

Theme orange-lt created by panic