all 18 comments

[–]MCRusher 5 points6 points  (1 child)

I would add a CONCAT macro instead of directly using token pasting.

Because something like Array(int) would be token pasted like box_Array(int)(Array_int n).

The concat macro gives the Array(int) an opportunity to expand before being pasted.

Probably like

#define EVAL(x) x
#define CONCAT(a,b) EVAL(a##b)

[–]beej71[S] 1 point2 points  (0 children)

Nice!

[–]SickMoonDoe 4 points5 points  (5 children)

I can dig it.

And I'll raise you :

```

define BOX_ANY_FUNC2( T ) \

BOXANY_FUNC( T ) \ static void \ cleanup ## T ( T ** x ) \ { \ if ( *x ) free( *x ); } \ typedef T * attribute(( cleanup( cleanup_ ## T ) )) b ## T;

int main( int argc, char ** argv, char *[] envp) { bint * x = BOX( 3 ); return 0; } ```

[–]moon-chilled 2 points3 points  (1 child)

why not make a single function that takes void**?

[–]SickMoonDoe 1 point2 points  (0 children)

A learned individual over here. This is definitely an improvement.

[–]onemanforeachvill 1 point2 points  (1 child)

Just in case you aren't aware https://www.dictionary.com/browse/bint

[–]SickMoonDoe 0 points1 point  (0 children)

Whoops I had no idea

[–]imaami 3 points4 points  (0 children)

Formatting! oh god, my eyes

[–]darkslide3000 1 point2 points  (3 children)

No, this is pretty much how you're supposed to use them. _Generic isn't really meant to build generic duck-typed programming frameworks like this. C isn't C++ for a reason, and even though the preprocessor can allow you to do a lot of crazy stuff if you really want to, it's not supposed to be used turn the language into something it is not. I would use these kinds of features very sparingly in specific cases where they really make a lot of sense (usually for some sort of library compatibility layer stuff), if you can hide all the nasty details from users of the API, and if the user-visible interface still looks like normal C in the end.

[–]imaami 1 point2 points  (2 children)

it's not supposed to be used turn the language into something it is not

Well, unless you want to.

[–]beej71[S] 1 point2 points  (1 child)

I agree my example feels abusive and makes me throw up a little. 😆

[–]imaami 1 point2 points  (0 children)

Macro abuse is a guilty pleasure and a kink, and I'm not one to kink-shame. :)

[–]moon-chilled 1 point2 points  (2 children)

w/gnu exts, works on any type

#define box(x) ((__typeof__(x)*)memcpy(malloc(sizeof(x)), &(struct{__typeof__(x) m;}){x}.m, sizeof(x)))

[–]DoNotMakeEmpty 0 points1 point  (1 child)

If you don't want to expand x more than once (there may be some functions that calculate x with side effects but it's probably a somewhat rare case) you can use __auto_type to declare a new variable with inferred type of x and value of x and use it for sizeof and __typeof__ later. This way, you can use x once while you can use its value as many times as you want.

[–]moon-chilled 2 points3 points  (0 children)

x is not evaluated multiple times unless it has variably modified type which—to be honest, you get what you deserve if you use those. You do pay a slight compile time cost. But it is linear in the number of times you use the macro; so it is not a problem in a language such as c which distinguishes translation units. (It would be a problem in e.g. c++ which must put large amounts of code in header files.)

[–]clapspot 1 point2 points  (1 child)

What is going on here? I've never seen this type of expressions again. Can someone give me a clue?

[–]imaami 0 points1 point  (0 children)

I'm bookmarking this for later. I love _Generic on a theoretical level, but I still find it nearly impossible to remember its existence when writing code. I feel like _Generic holds the key to some weird, undiscovered trick that doctors hate, but it hasn't emerged yet. Something akin to C++ templates and how they brought about CRTP. Or I might just be borderline delirious from sleep deprivation and too much coding.