Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Bunny Cuddlin
Dec 12, 2004

Suspicious Dish posted:

The preprocessor really should always insert parens for you automatically. I can't think of a single reason for it not to.



code:
#ifdef DEBUG
#define DEBUG_PRINT(x) printf("%s" x, whatever);
#else
#define DEBUG_PRINT(x)
#endif

Adbot
ADBOT LOVES YOU

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

That Turkey Story posted:

You mean have macros always expand to something parenthesized? That wouldn't work -- the are lots of times where you don't want the expansion to result in something that's parenthesized I.E. almost anything that doesn't result in an expression.

I meant "when the preprocessor results in an expression, parenthesize it automatically".

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Suspicious Dish posted:

I meant "when the preprocessor results in an expression, parenthesize it automatically".
Determining whether or not a thing is a valid expression is way more complicated than anything the C preprocessor does.

Bunny Cuddlin
Dec 12, 2004

Suspicious Dish posted:

I meant "when the preprocessor results in an expression, parenthesize it automatically".

code:
#ifdef DEBUG
#define RELEASETYPE development
#else
#define RELEASETYPE production
#endif

typedef enum { release, production } releasetype;

errno = -1;

int main(int argc, char* argv[]) {
    doStuff(values, RELEASETYPE);
    if (errno >= 0) {
        Handle_RELEASETYPE_Error(errno, otherstuff);
    }
}
I know it's contrived but you get the idea.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Gigantic Slut Man posted:

code:
Handle_RELEASETYPE_Error(errno, otherstuff);
I know it's contrived but you get the idea.

It's so contrived it won't compile!

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Plorkyeran posted:

Determining whether or not a thing is a valid expression is way more complicated than anything the C preprocessor does.

I don't think so. It already takes comments and strings into account, and certainly parses a lot of C's existing structure. Determining whether the macro expansion will result in an expression isn't that hard, I don't think.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Gigantic Slut Man posted:

code:
#ifdef DEBUG
#define RELEASETYPE development
#else
#define RELEASETYPE production
#endif

typedef enum { release, production } releasetype;

errno = -1;

int main(int argc, char* argv[]) {
    doStuff(values, RELEASETYPE);
    if (errno >= 0) {
        Handle_RELEASETYPE_Error(errno, otherstuff);
    }
}
I know it's contrived but you get the idea.

IIRC you'd need ## to do that, not just a define

Bunny Cuddlin
Dec 12, 2004

Suspicious Dish posted:

It's so contrived it won't compile!

durr. Brain fart. Whatever, #DEFINE TWOPLUSTWO 2 + 2

a = TWOPLUSTWO * 5

Doctor w-rw-rw-
Jun 24, 2008

Suspicious Dish posted:

I don't think so. It already takes comments and strings into account, and certainly parses a lot of C's existing structure. Determining whether the macro expansion will result in an expression isn't that hard, I don't think.

No. If you forget parentheses, braces, or a semicolon, it is your fuckup and you should fix it. The preprocessor should do a simple job and do it well. That is C's place among the languages: To do as it is told and follow rules no simpler and no more complex than necessary.

Manning up, and learning to macro is better than getting used to parentheses magic.

P.S. do { /* code goes here */ } while(false) is a pretty neat trick to use for non-expression macros.

KaneTW
Dec 2, 2011

Gigantic Slut Man posted:

durr. Brain fart. Whatever, #DEFINE TWOPLUSTWO 2 + 2

a = TWOPLUSTWO * 5

Which by any reasonable logic should result in a = 20, not a = 12. But yeah, putting parenthesis around defines is pretty much your own responsibility.

Bunny Cuddlin
Dec 12, 2004

KaneTW posted:

Which by any reasonable logic should result in a = 20, not a = 12. But yeah, putting parenthesis around defines is pretty much your own responsibility.

No, because it's a macro language and not a programming language. It doesn't evaluate statements, that's not part of what it sets out to do. It's a contrived example that shows where something which is an expression has its meaning changed by inserting parenthesies, please do not focus on my specific example.

Bunny Cuddlin fucked around with this message at 01:05 on Sep 19, 2012

KaneTW
Dec 2, 2011

E: never mind, this is silly

Vanadium
Jan 8, 2005

Doctor w-rw-rw- posted:

Manning up, and learning to macro is better than getting used to parentheses magic.

P.S. do { /* code goes here */ } while(false) is a pretty neat trick to use for non-expression macros.

or we could get a modern compile-time shenanigans system where we don't have to teach people to place bullshit parentheses everywhere and abuse loops

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Gigantic Slut Man posted:

durr. Brain fart. Whatever, #DEFINE TWOPLUSTWO 2 + 2

a = TWOPLUSTWO * 5

Thanks for proving my point for me.

Gigantic Slut Man posted:

No, because it's a macro language and not a programming language. It doesn't evaluate statements, that's not part of what it sets out to do.

Who said it should?

Doctor w-rw-rw- posted:

No. If you forget parentheses, braces, or a semicolon, it is your fuckup and you should fix it.

Fixing various syntax errors is not the goal of the preprocessor, nor do I believe it should become one.

Doctor w-rw-rw- posted:

The preprocessor should do a simple job and do it well. That is C's place among the languages: To do as it is told and follow rules no simpler and no more complex than necessary.

The rules the preprocessor follows aren't that simple already. There's no reason we can't add a few more

Doctor w-rw-rw- posted:

P.S. do { /* code goes here */ } while(false) is a pretty neat trick to use for non-expression macros.

The fact that that technique exists and is prevalent as it is, despite being complete nonsense, argues to me that the preprocessor deserves a bit more power and responsibility.

If the do...while syntax didn't have the exact syntax it does, this trick wouldn't work. It's abusing an unintended part of the grammar not for its functionality, but for its syntax.

Vanadium
Jan 8, 2005

It's hardly a thing I'd propose for literally the C preprocessor but trying to romanticise its behavior beyond it being more trouble than it'd be worth to replace it is silly.

Bunny Cuddlin
Dec 12, 2004
I suppose we just have differing ideas about the preprocessor: I believe it should be as simple as possible so that you can do your programming in, you know, the programming language it supports. Adding a mini-parser to the preprocessor sounds like a horrible idea to me.

hobbesmaster
Jan 28, 2008

Vanadium posted:

It's hardly a thing I'd propose for literally the C preprocessor but trying to romanticise its behavior beyond it being more trouble than it'd be worth to replace it is silly.

Abusing the C preprocessor is as valid a sport as golf. :colbert:

that awful man
Feb 18, 2007

YOSPOS, bitch

Suspicious Dish posted:

The rules the preprocessor follows aren't that simple already. There's no reason we can't add a few more

Yeah, why not make an incompatible change to the language's semantics. Who cares if existing code won't work anymore?

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Gigantic Slut Man posted:

I suppose we just have differing ideas about the preprocessor: I believe it should be as simple as possible so that you can do your programming in, you know, the programming language it supports. Adding a mini-parser to the preprocessor sounds like a horrible idea to me.

That's a respectable idea, but the problem is that the C preprocessor isn't simple, already.

I do think that C needs something that enables metaprogramming a bit more than its current processor, but I'm not sure what that should entail.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
C provides a lexical (token-based) preprocessor. What you want is a non-lexical preprocessor, i.e. not really a preprocessor at all so much as a compile-time metaprogramming system capable of generating, suppressing, and modifying arbitrary language structures. That is possible, but it's far, far more complicated and substantially more sophisticated than what people were doing in compiled languages 35 years ago; in fact, the only significant compiled languages I know of with that ability are in the LISP family.

Bunny Cuddlin
Dec 12, 2004

Suspicious Dish posted:

That's a respectable idea, but the problem is that the C preprocessor isn't simple, already.

It's simple compared to what you want. Right now all it needs is the result of the lexxer, you want to add a parser. That's another layer of complexity entirely.

That Turkey Story
Mar 30, 2003

Suspicious Dish posted:

I don't think so. It already takes comments and strings into account, and certainly parses a lot of C's existing structure. Determining whether the macro expansion will result in an expression isn't that hard, I don't think.

Those are all very trivial. The preprocessor basically has no knowledge of C++ or C for that matter. It doesn't even know what an expression is let alone how to differentiate one from other code. This is actually very complicated in C++. For a simple example:

int( foo )

What is that? Is that an expression or is it a type? It depends on what foo is. If foo is a type, then int( foo ) is also a type. If foo is not a type, then that's an expression constructing an int from foo. Also, what about macros that are partial or potentially partial:

#define foo -a

What is that? Is that -a or is that the second part of a subtraction? There's a ton more stuff to consider other than what I've shown that make it impossible to determine whether or not the user actually wants parentheses, even in the case of expressions.

Suspicious Dish posted:

I do think that C needs something that enables metaprogramming a bit more than its current processor, but I'm not sure what that should entail.

I'm with you there. Right now the C preprocessor is technically Turing complete, but it's still a bitch to do complicated stuff with.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

That Turkey Story posted:

Those are all very trivial. The preprocessor basically has no knowledge of C++ or C for that matter.

It has some language semantics embedded in it, but yeah, I guess it can be done with only a lexer, transforming the token stream as it goes through.

That Turkey Story posted:

It doesn't even know what an expression is let alone how to differentiate one from other code. This is actually very complicated in C++. For a simple example:

int( foo )

What is that? Is that an expression or is it a type? It depends on what foo is. If foo is a type, then int( foo ) is also a type. If foo is not a type, then that's an expression constructing an int from foo.

There's a reason I don't write C++.

That Turkey Story posted:

Also, what about macros that are partial or potentially partial:

#define foo -a

Yeah, I guess I didn't think of all those edge cases.

That Turkey Story posted:

I'm with you there. Right now the C preprocessor is technically Turing complete, but it's still a bitch to do complicated stuff with.

Isn't looping sort of required to be turing complete?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
The standard tries to disallow recursive macros, but you can use some clever tricks to effectively allow recursion up to a fixed stack size.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Jabor posted:

The standard tries to disallow recursive macros, but you can use some clever tricks to effectively allow recursion up to a fixed stack size.

But you can't keep state when looping, which I thought was necessary.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Suspicious Dish posted:

But you can't keep state when looping, which I thought was necessary.

You'd be surprised what you can achieve if you abuse token pasting enough.

mjau
Aug 8, 2008

Suspicious Dish posted:

Isn't looping sort of required to be turing complete?

code:
#include __FILE__
:v:

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Jabor posted:

You'd be surprised what you can achieve if you abuse token pasting enough.

I doubt I'd be.

That Turkey Story
Mar 30, 2003

Suspicious Dish posted:

But you can't keep state when looping, which I thought was necessary.

Hmm? You pass along the state as macro arguments. You can emulate fold with the C preprocessor -- Boost.Preprocessor has an implementation. In fact, you can emulate all sorts of constructs up to a given limit. For instance, you can implement recursion in the more general sense than just fold, you can do while, for each, you can even emulate mutability, and more (Chaos even has lambda functions)!.

Of course, most of these library-emulated constructs have limits and you "recurse" up to a given depth. You could probably argue that because of this it is not really Turing complete, but that ends up being somewhat unimportant especially since all compilers effectively have internal limits anyway. The only difference is that the limits with the C preprocessor for recursion are library-dependent as opposed to compiler dependent. In practice, that difference doesn't actually matter.

That Turkey Story fucked around with this message at 07:15 on Sep 19, 2012

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

That Turkey Story posted:

Hmm? You pass along the state as macro arguments.

But the only way you can evaluate macro arguments is by making them expand to other macros. And even then, you can't do any computation with that, only concatenation.

Wait a minute...

C code:
#define __N_ 0
#define __N_I 1
#define __N_II 2
#define __N_III 3
#define __N_IIII 4
#define __N_IIIII 5
#define __N_IIIIII 6

/* ... */

#define __D_0
#define __D_1 I
#define __D_2 II
#define __D_3 III
#define __D_4 IIII
#define __D_5 IIIII
#define __D_6 IIIIII

/* ... */

#define PASTE_ARGS(x, y) x##y
#define PASTE(x, y) PASTE_ARGS(x, y)

#define D2N(x) PASTE(__D_, x)

#define INCREMENT(x) x##I
#define NTIMES_N(count, expr) expr NTIMES_N(INCREMENT(x##I), expr)

#define NTIMES(count, expr) NTIMES_N(D2N(count), expr)
But I'm having a hard time finding a way to make the termination stop.

I haven't looked at your crazy fold implementation. Am I anywhere near the solution?

Pilsner
Nov 23, 2002

Can someone explain the point of all those hoops and hacks with the pre-processor in C? I can't see it bringing anything but a horror of entangled dependancies and messy code, and I can't recall ever missing the feature in C#. Is there anything with macros you can't just write properly in normal code?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Pilsner posted:

Can someone explain the point of all those hoops and hacks with the pre-processor in C? I can't see it bringing anything but a horror of entangled dependancies and messy code, and I can't recall ever missing the feature in C#. Is there anything with macros you can't just write properly in normal code?

Suppose you wanted to write a function that accepted a heterogeneous sequence of parameters, did something to them, and passed it on to something else.

Generics + varargs solve the problem for a homogeneous parameter list, of course, but if you want to handle heterogeneous parameters then you're stuck writing a separate function for each different number of parameters, all of which are close to identical.

This is where metaprogramming (of which heavy macro use is an example) comes in handy. It's typically not especially useful for application development, but it's really good for building highly-reusable libraries.

My name aint Jerry
Sep 4, 2011

Good job with notjerry.org, Not Jerry. Here is not-a-trophy for you.

Pilsner posted:

Can someone explain the point of all those hoops and hacks with the pre-processor in C? I can't see it bringing anything but a horror of entangled dependancies and messy code, and I can't recall ever missing the feature in C#. Is there anything with macros you can't just write properly in normal code?

Of course not, whatever you write in macro ends up as code, so you could do with the expansion directly.

It's easy to fabricate horror stories about pre-processor macros, which only emphasize the fact that care should be taken when writing macros.

There are plenty of examples of macro packages that help write easier to read and maintain code. And that's where the pre-processor is useful. I was really fond of windowsx.h, in the ancient times when I was writing win16/32 code in C. That was a neat macro package in an ocean of messy header files.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Pilsner posted:

Can someone explain the point of all those hoops and hacks with the pre-processor in C? I can't see it bringing anything but a horror of entangled dependancies and messy code, and I can't recall ever missing the feature in C#. Is there anything with macros you can't just write properly in normal code?

Hopefully this code will never be used in production. It's just a fun puzzle for me: do arithmetic and also repetition with only concatenation.

Sebbe
Feb 29, 2004

A good example of clever macro use I found was in the Teeworlds source.

Here, all game variables are defined in a header file, using some macro functions:

C code:
MACRO_CONFIG_STR(PlayerName, player_name, 16, "nameless tee", CFGFLAG_SAVE|CFGFLAG_CLIENT, "Name of the player")
MACRO_CONFIG_STR(PlayerClan, player_clan, 12, "", CFGFLAG_SAVE|CFGFLAG_CLIENT, "Clan of the player")
MACRO_CONFIG_INT(PlayerCountry, player_country, -1, -1, 1000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Country of the player")
MACRO_CONFIG_STR(Password, password, 32, "", CFGFLAG_CLIENT|CFGFLAG_SERVER, "Password to the server")
MACRO_CONFIG_STR(Logfile, logfile, 128, "", CFGFLAG_SAVE|CFGFLAG_CLIENT|CFGFLAG_SERVER, "Filename to log all output to")
MACRO_CONFIG_INT(ConsoleOutputLevel, console_output_level, 0, 0, 2, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Adjusts the amount of information in the console")

// ...
This header file contains all information about all game variables in a structured manner. This information is then used in different places in the code for different purposes, by redefining the MACRO_CONFIG_(INT/STR) macros: Like so.

One could argue if there are better ways of doing it, but it works and provides a convenient location to easily define new variables with a pretty clean syntax, so I'd call it a pretty good use of macros.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
Known as X-Macros.

PrBacterio
Jul 19, 2000

Jabor posted:

Suppose you wanted to write a function that accepted a heterogeneous sequence of parameters, did something to them, and passed it on to something else.

Generics + varargs solve the problem for a homogeneous parameter list, of course, but if you want to handle heterogeneous parameters then you're stuck writing a separate function for each different number of parameters, all of which are close to identical.
Wouldn't it also be possible to solve this with generics+currying in some fashion?

Zombywuf
Mar 29, 2008

Jabor posted:

Generics + varargs solve the problem for a homogeneous parameter list, of course, but if you want to handle heterogeneous parameters then you're stuck writing a separate function for each different number of parameters, all of which are close to identical.

Er whut?

code:
template<class ...Args>
footype my_function(Args... argpack) {
  ...
}

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Zombywuf posted:

Er whut?

code:
template<class ...Args>
footype my_function(Args... argpack) {
  ...
}

"What's the point of metaprogramming? See, you can do the exact same thing by using this other metaprogramming feature!"

Adbot
ADBOT LOVES YOU

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Realtalk, Pilsner mentioned C# so I picked something that C#'s existing facilities don't handle cleanly. Yes variadic templates handle that specific example pretty well.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply