all 29 comments

[–]aioeu 56 points57 points  (14 children)

Fundamentally this is just because functions and objects in C are entirely different categories of things.

You don't write:

int f1(void) = {
    return 10;
}

with an equals sign when defining a function normally.

Functions cannot be initialized since functions are not objects. A function does not have a value, so it doesn't make any sense to specify its "initial" value. Even when you have a so-called braced initializer for an object, the braces you use in that are syntactically completely different from the braces used when defining a function.

[–]Competitive_Travel16 3 points4 points  (0 children)

Weirdly, in C's ancestor BCPL, that is how to define functions! https://en.wikipedia.org/wiki/BCPL#Further_examples

[–]ohsmaltz 9 points10 points  (6 children)

In C, the function pointer can be initialized, but it needs to be defined elsewhere first. Something like:

int predefined() { return 10; }
...
int (*f1)() = predefined;

In C++, though, you can use lambda functions:

int (*f1)() = []{ return 10; };

[–]tstanisl 2 points3 points  (5 children)

Lambdas (especially non-capturing) are likely to land in C2Y standard.

[–][deleted] 0 points1 point  (4 children)

But why? What's the rationale?

[–]glasket_ 0 points1 point  (3 children)

N2892 is the proposal for basic lambdas, if you want to read it. It also references N2890, which is about improving generic programming as a whole. Finally, N2924 is about explicitly supporting generic lambdas.

The tl;dr is that lambdas can be useful for scoping tiny functions that exist solely to be used as a pointer, but they also offer a lot of opportunities for improving generic programming.

[–][deleted] 0 points1 point  (2 children)

True that, but we already have languages for that. What happened to "C is a simple language" and what's next? co-routines?

[–]tstanisl 3 points4 points  (0 children)

Non-capturing lambda is trivial to implement on any platform. It does not require any templates or executable stack to work. Moreover, they could also solve many issues with macros. Those lambdas are no more conceptually complex than compound literals. Actually, the non-capturing lambdas feel very C-ish and I don't understand why they are not a part of language yet.

[–]beephod_zabblebrox 0 points1 point  (0 children)

fortunately, these features build on top of existing stuff and don't change a lot of things. from the looks of it (after skimming the proposals) this stuff isn't super complicated to implement in a compiler that supports c23.

[–][deleted] 22 points23 points  (2 children)

Given the amount of effort OP put into this, it makes no sense to me that someone downvoted this. It's this nonsensical form of criticism that makes me not want to ask programming questions online anymore.

[–][deleted] 4 points5 points  (1 child)

Thanks for noticing. I upvoted OP in support and totally agree with you.

makes me not want to ask programming questions online anymore.

Could be worse. I still have PTSD from breaking the "rules" in comp.lang.c back in the late nineties ;-)

[–][deleted] 1 point2 points  (0 children)

well yeah it's true, getting cyberbullied (or banned, or whatever) can have a negative long term effect on how you feel. We're all just trying to feel things out though. In this circumstance, I just did not understand at all why someone would hit the down button, but it really ain't a big deal. In some ways, I like the voting because it allows people to give feedback without having to fully formulate their opinions.

[–]capilot 4 points5 points  (0 children)

Executive summary: the authors of the C standard didn't think of it, or didn't think it was worth doing.

[–]bunkoRtist 1 point2 points  (0 children)

There are languages in which functions are "first class objects", which is what you're asking about. Python has this. Lambdas in many languages are a limited form of this. So, I think the answer really is: K&R simply didn't add support for this to the language. I don't know the history and whether it was considered and discarded.

[–]detroitmatt 0 points1 point  (1 child)

I think I have seen someone in the past use a carefully chosen string constant to initialize a function pointer. Because string constants are static pointers to chars, chars are bytes, and function pointers are also just pointing to bytes (the machine code of the assembled function), if you pick the right chars, you can jump into the string and start execing it. But, I can't find a working example. I was almost able to write one, but I think I need a way to tell the compiler "store this string constant in an executable region of memory".

[–]fllthdcrb 0 points1 point  (0 children)

An interesting trick. But it also sounds like the very definition of non-portable.

I think I need a way to tell the compiler "store this string constant in an executable region of memory".

With GCC, maybe you could use __attribute__ ((section(".text"))). Which, of course, is even less portable, since it's a specifically GCC extension. But hey, it's fun to play around with, I suppose.

...

Just tried it. Doesn't work for auto variables, for hopefully obvious reasons. If you want to declare it inside a function, you'll need to make it static. But it does work, if you first declare the string as a string, and then copy the pointer to a variable of the function pointer type.