That would allow cleanup and other such actions without resorting to such hacks as: "goto cleanup" pattern, separate functions, fake for loop to break out of, ...
That would allow cleanup and other such actions without resorting to such hacks as: "goto cleanup" pattern, separate functions, fake for loop to break out of, ...
It would be nice to have this be a part of the standard.
You can do it in the 20-year-old version of it, and draft versions many years before that.
Edit: Ah, I see; you're more worried about them turning C into the next C++ :) I might even agree some days.
A modern C++ compiler will have all sorts of issues with fundamental C idioms, and depending on C++ is a very different story from depending on C.
I maintain a significant body of code which compiles as C or C++. The executable size and performance are about the same.
A C++ compiler will, of course, have "issues" with C99 and C11 features, that's for sure.
Here let me note that I have not gone out of the way to disable anything in C++. I have not disabled EH in the compiler, or RTTI or anything. Yet, the executable size is close to the C one, and the performance is basically the same.
well, did you know that for instance the windows C library was implemented in C++ ? and yet we don't see it throwing exceptions left and right.
What they don't share is mindset; C is all about keeping it simple, I don't even know what C++ is about any more, but it sure isn't simple. Many fundamental tricks that are routinely pulled in C require jumping through plenty of hoops to keep a modern C++ compiler happy.
Speaking of interop, calling into C from other languages is very different from calling into C++. Yes, you can write C wrappers, but it's rarely done. And the further the language drifts into template lala land, the more tricky it gets.
Not in my experience. Currently my man open source project consists of some 70,000 of C which compiles as C++. Maintaining C++ compatibility takes very little effort. I tend to switch to C++ before a release, to catch regressions. Often there is nothing. The most I spend is maybe five to ten minutes fixing some minor things. Some of those minor things have nothing to do with C versus C++ like signed/unsigned warnings.
Note that these signed/unsigned warnings from GNU C++ actually found a real problem: I had code which assumed WEOF was negative. (It was originally char based code that was switched to wchar_t; of course EOF constant in the narrow character world is negative.) The GNU C++ compiler also identified the situation in the same code that a variable that should have been wint_t was mistakenly int.
The classic struct hack looks like:
struct header {
size_t size;
char data[1]; // not [0]
};
the size of the structure to just before data is offsetof(struct header, data).Automatic void casts are a misfeature in both languages; more so in C. In code that I control, I use a pointer to a character type as an "any memory" type, so that it requires a cast in both directions:
E.g.
typedef unsigned char mem_t;
a custom allocator or allocator wrapper will return a pointer to mem_t.I use macros for casts, which compile to the classic C cast in C, and the more restricted casts in C++:
#ifdef __cplusplus
#define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR))
#define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR))
#define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR))
#else
#define strip_qual(TYPE, EXPR) ((TYPE) (EXPR))
#define convert(TYPE, EXPR) ((TYPE) (EXPR))
#define coerce(TYPE, EXPR) ((TYPE) (EXPR))
#endif
The GNU C++ compiler has a cool feature: -Wold-style-cast. With this I can pinpoint uses of the casting notation, and then replace them with these macros.The stupid void star thing and its conversion rules should never have been invented. C++'s treatment of it is more sane, at least, by working without a cast in only one direction.
What's really awful is official API's that use void star for opaque handles. The Kronos Group's OpenMax is one of these. You can mix up different kinds of handles for different objects and the calls will compile.
That's like your opinion, plenty of C programmers worth their salt would disagree with you.
Look, I'm not saying it's impossible to write code that compiles both as C and C++. The same is true of many other languages. The point is that you can't write C and expect it to be valid C++, which was the only thing I claimed.
Then my project grows to the point where I need to do some simple string operations.
At which point I remember the wonderful simplicity of garbage collected, high level languages...
/**
* GCC and Clang extension to call cleanup function at exit
* from the function with pointer to given function as argument.
*/
#define defer(func) __attribute__((cleanup(func)))
#ifdef _CRUST_TESTS
// Sample destructor, to test defer
static void _tst_charp_destroy(char * * value) {
if(*value) {
free(*value);
*value = NULL;
}
}
// Test case
it(defer, "must deallocate object at the end of the function") {
defer(_tst_charp_destroy) char * s = calloc(1, sizeof(char));
(void)s;
}
#endifD has scope(exit){...} which is similar to constructs like defer {...}
Many things can be done in some form with macros and the C11 generic keyword if they have to be, but defering statements to run on scope exit is still elusive as something that can be relied upon.
Many programmers like myself have no problem with it whatsoever.
Change in a key infrastructural component like this is only destabilizing.
The ISO C people should have the decency to disband and work on their pet language research projects in private.
The only guaranteed way your compiler won't break your code is if it's left alone.
Also, gratuitous changes to the compiler can break things that affect C90 operation. There is a risk.
Adding simple abstractions which don't hide complexity in the underlying assembly is a huge productivity and correctness boost. Not that it matters anyways; modern optimizers are always going to do things that absolutely bend your brain.
Wouldn't that be nice if you could use a `scope(exit) {}` instead of accidentally missing two or three `goto cleanup_7;` which result in an RCE?
I would absolutely love a standards-compliant way to scope-guard sections of code. It'd make huge swaths of C code simpler; it's even in enough demand that Clang and GCC implement as their own extensions.
I can gladly provide a couple of examples.
Also the draft C2x standard does away with K&R declarations, which will be another compatibility break.
Regarding C++:
- auto changed its meaning on C++11
- export templates were removed in C++11
- exception specifications were deprecated in C++11, removed in C++17 and might do a come back in C++23 with value based exceptions
- gets() got removed in C++11
- declspec and auto had a small semantic difference, settled in C++17
- initializer lists introduced in C++11 changed their auto deduction type in C++17
- the required implementation semantics for std::string in C++11 broke COW in compilers like GCC.
Just a small list, there are a couple more.
There's no evidence of this. There's just existing code. Ok. There's existing code in lots of other languages with different syntax (large and small differences). So what?
The latest video about Oden was a fantastic primer on QoL changes that should be standard, but there are people who always think what they learned is optimal. These are the same people who trivialize evidence to the contrary, in defense of their particular viewpoint.
Alright. Glad we cleared this whole thing up.
Nope; I will be writing in "it". What you obviously want is to be writing in something other than "it". You basically want to be able to write Rust, Go or D into a file that has a .c suffix and is passed through a preprocessor.
The issue with cleanup on scope exit is that this introduces ambiguous code-flows. You would need to demonstrate a strong advantage, beyond making life easier for the writer of the code.
EDIT: Sorry for the confusion, I misread the article and thought this was about C++2x.
But who are we to ask..? Just programmers, i.e. mere mortals nobody really cares about. :-)
But then you also want templates of course to get rid of your void*. And oh, wait, what's that? A cross-platform thread implementation (well, sort of, depends on platform)? A string thing which I can search without strstr? Anonymous functions which capture? Auto? Gimme gimme :]
C++ is not a strict superset of C. You actually have to cast void pointers, for example.
> But then you also want templates of course to get rid of your void*.
No, actually, I think I can live without that, but thank you.
> And oh, wait, what's that? A cross-platform thread implementation (well, sort of, depends on platform)?
C11, threads.h. Been there, got that.
> A string thing which I can search without strstr?
Okay, I'll give you that, string handling is hell.
> Anonymous functions which capture?
Have their uses, but I'm not sure if C is really the right place for it.
> Auto?
auto (as used in C++11 and later) is a solution in need of a problem in C. When you don't have piles of templates and iterators, you also tend not to need to automatically derive types. In a world where signed/unsigned integer comparison can have fatal consequences, you probably do want to be very sure about your types.
I think you flipped this :) ?
I know that. I use both C and C++ practically daily. The post was partly joking. But only partly (for example of course I could live without templates if really needed but seriously they make some jobs a lot better and easier). Hence I aptly phrased it some kind of C hoping (idly it seems) no one would trip over it because it's obviously not C.
Because some platforms I've used it on did't have proper C++ support. Or because a project I contribute to is already written in C. Or because of limited resources. Etc.
I'm not really understanding how wanting one little thing from C++ implies diving all the way in.
It's just an example of a possible train of thought. And I wouldn't call something like templates 'one little thing'. So suppose there's a choice between both, and no limit on resources etc, and I could go for everything C but templates could make everything easier then just going for C++ instead is an option. Even when not going 'all in' and writing what looks like standard C + template support.
Agreed. But templates aren't the one little thing, they're something you said would be 'next'. The 'one little thing' is a way to replace the GOTOs used for releasing resources. I think it's an easy argument that when people are repeatedly building a pattern out of GOTO, there's a gap in the control flow tools that a language gives you.
auto was already in vanishing disuse in C at the time ANSI C came out in 1989.
The C++ use of auto resurrects an aspect of the way auto was used in the C predecessor languages B and NB.
In these pre-C languages, everything was an integer cell. A declaration of local variables looked like this:
auto x, y;
the auto meant automatic storage (stack), but the real purpose here is syntactic: the auto is a declaration specifier, which makes the above construct a declaration. There is no indication of type, because it is implicit. Without the auto it would look like a comma expression with no effect.This implicit typing survived into C for "implicit int" return values, like "main () {...}". But type specifiers were introduced and became mandatory in declarations, and so auto became unnecessary verbiage since all it did now was specify a storage class that was already the default one.
C++ resurrect the syntactic use of auto in a way: once again, it provides declaration syntax that allows the type specifier to be omitted. This time, of course, that type is inferred rather than assumed integer.
https://stackoverflow.com/questions/2053029/how-exactly-does...
If they would add that feature, you could use macros to get constructor and destructor like behavior (as long as it's within the same scope, you could write a macro that constructs your object, and in addition contains something like "at scope exit: run this function"), which would be super useful and as far as I'm aware not very complex for the compiler (as all they have to do is run some code whenever exiting scope) nor very far outside of the spirit of C (it's still very low level, just a small convenience feature with interesting implications, especially when used with macros).
It is the result of starting with C, and then accommodating a massive, sustained sequence of feature requests, exactly like ones we are seeing in this thread.
Everyone thinks that if just their pet feature request is added to C and everyone else's ideas are rejected, it will still be C.
This idea doesn't seem to be in that spirit to me. It's not trying to do something radical like, say, adding OOP semantics to C. It's suggesting that C, a structured programming language, get a feature designed to improve the ergonomics for people doing structured programming in C.
https://www.boost.org/doc/libs/release/libs/scope_exit/doc/h...
// WTFPL
class Finally {
std::function<void()> f;
public:
Finally(std::function<void()> f) : f{f} {}
~Finally() {f();}
void disable() { f = [](){}; }
};
Which looks much prettier: socket* s = open_socket(); // or whatever
Finally cleanup_socket{[](){ close_socket(s);}};
// optionally, to keep it alive:
cleanup_socket.disable();
Am typing on mobile. No guarantees about syntax errors. I still need to look into where the right places to put r value references and/or std::move are, but for the most part, I never put anything other than a pointer in the closure so I'm not worried about copy constructor cost. auto cleanup_socket = make_scope_guard([&]{ close_socket(s); });
Searching for scope_guard yields lots of alternative implementations. std::pair p{"aaa", 123};
and Finally guard{[]{cleanup();}};
without specifying template arguments.[1] https://en.cppreference.com/w/cpp/language/class_template_ar...
I disagree.
> to run code when leaving a scope, no matter how you leave
This, and various other features, were already added to C long ago. The resulting dialect was called C++.
Are you implying that people who want new features in C should just migrate to C++ because it has even more features? Or that C is perfect as-is and anyone who wants to add new features to it should bug off to another language? Or that this particular feature is somehow equivalent to (or a slippery slope toward) adding a whole set of OOP features to C, so we might as well take that to its logical conclusion?
A single, clearly articulated response would do a lot more than a fusillade of terse barbs to help others understand why you think this is a bad idea.