Progress on C23
thephd.dev
thephd.dev
const unsigned magical_number = 0b0110'0001'0110'0011'0110'0001'0110'0010;
Finally. It’s mystifying to me why this took so long to add; not everyone is fluent in translating hex digits to binary nybbles on the fly. This will greatly help with clearly defining and manipulating bitfields. The fact that digit separators can be placed arbitrarily will further help delimit fields of variable width, e.g. # A B C D
uint8_t flags = 0b00’1’0’11’01;
A and B are binary fields; C and D are quaternary fields. The first two bits are padding. This is a lot more readable than uint8_t flags = 0x2D;I predict people will use it for a while, then abandon it.
https://github.com/ityonemo/Primes/blob/f157b63d91375c62f110...
I've also verified that binary representations of unusual datatypes are correct and have the expected properties (~>5 yr ago, paid gig, actually my first paid gig):
https://github.com/interplanetary-robot/SigmoidNumbers/blob/...
https://github.com/interplanetary-robot/SigmoidNumbers/blob/...
Extremely happy with it in all cases. You can't convince me otherwise. Zig and Julia would be poorer languages if not for binary literals. My life would have been more annoying without it. It's a tool I have reached for in the past and will continue reaching for when appropriate and tasteful, I have not "abandoned it". At least, I'm one datapoint that refutes your assertion.
There's always one!
BTW, D does support 0b:
I haven’t used the C2x version, but one thing I expect them to be useful for is self-documentation of enums representing bitmask values.
I used to do that, and wound up back using hex. Hex is easier to read for me, as I don't have to count the digits.
struct Foo{
bool some_flag : 1;
bool other_flag : 1;
....
}
?Turned out that it was actually significantly faster to use one byte per boolean and forgo the masking operations. I assume the processor was just good enough at keeping its cache filled in that particular workload, so the additional masking operations just slowed things down. So I understand why you might not want a compiler to automatically do this.
struct X {
_BitInt(1) a;
_BitInt(1) b;
};
do now?https://twitter.com/__phantomderp/status/1381314735174524928
And, very recently, I have begun to scheme and agitate for a feature similar to what your article proposes:
https://twitter.com/__phantomderp/status/1424466518797135876
I am not sure people will go for `..`, and I would also like to find a way to enable composition and multi-dimensionality in an easier fashion (nesting arrays, for example, does not require that all of the memory is laid out perfectly flat. This is the case in both C and C++, and is taken advantage of by e.g. ASan and other memory-shadowing runtimes that add shadowing cushion around each array member).
As a Standards Committee person, I can't really just demand "and this will go into the standard"; our charter requires 2 existing C compilers/stdlibs to implement the thing (unless the thing is so dead-simple we can just shake hands and implement it because it's not contentious) and then, after that, requires consensus (which is its own roadblock to getting things done when someone doesn't like the syntax/way-you-are-doing-it/gets-in-the-way-of-their-implementation).
So, for example, if the C parser in D were to support this syntax, and someone else were to support some kind of syntax for this, and they all got together and wrote a paper for this idea, that would count as two implementations..........
Hint hint. Wink wink. Nudge nudge? 0:D
The spec, the implementation, and using it. It's by far the simplest scheme I've ever seen proposed for C. You can see this from the article.
I suppose I could add it to D's ImportC:
https://dlang.org/spec/importc.html
even though ImportC's charter is to implement C11 as it stands and not fix anything.
But would the committee accept DasBetterC as an implementation?
https://dlang.org/spec/betterc.html
DasBetterC does implement the slices.
I think getting this feature into one other implementation and then writing a paper on it would help. Unfortunately, the cutoff for "new papers that must be submitted to be considered for C23" is October, so there's not a LOT of time, so we'd need to find a 2nd implementation quick-fast, and then write the proposal quick-fast too!
https://support.apple.com/guide/security/memory-safe-iboot-i...
Apple (and others) have also very strongly informed us of the zeroing-things-out work they've done and how it saves them quite a bit of problems. There are folks on the Committee who value their already-existing users and implementations more, where indeterminate initialization provides them the performance and control they like. They also don't want to make those people have to change their code to init things. It's not a direction I agree with, but you have to remember that people like me have a much larger burden of proof. Indeterminate initialization is the status quo, and changing the status quo requires a paper, attending meetings, convincing others, and passing a vote. It's very much an uphill battle, and you have to bring a LOT of evidence to the table to fix it, and even after you bring that evidence you're required to prove it deserves to be in the standard. A lot of work!
For initialization, I am hoping to standardize "= {}" as a way to guarantee a proper static initialization. (Paper here, but needs some more work: https://thephd.dev/_vendor/future_cxx/papers/C%20-%20Consist...) Committee has received it favorably, and it should make C23.
For other things, you might need to lean on C23's attribute feature (e.g. "[[clang::must_initialize]]" and stuff) to provide some of that functionality. Not quite ideal, but attributes have standard placement and are infinitely extensible by implementations, so it gives vendors room to provide users what they need while the Standards Committee chews through proposal after proposal to get things done.
Hopefully this is a little helpful to you about the process!
Says to me the problem is the people on the standards committee.
And then let programmers decide if they want to live in the dark ages.
C'mon, EVERY other language I've ever worked with that had them uses underscores.
Why did you do this =(
Grateful there is now any symbol for this, but this an incredibly un-intuitive one.
Programming languages use underscores, (most) countries use commas (in varying decimal group positions).
What a confusing choice.
I then shift blame to whomever decided that was a good idea for C++, tossing it on the towering pile of similar questions directed towards C++'s architecture.
auto operator""_01(unsigned long long l) {
return 0;
}
int x = 100_01; // x == 0
so, as always, backward compat :D(grepping in my ~ I see at least one occurence of `operator "" _0b` and if you allow `_0b` it's going to be hard to justify not allowing `_0123456`).
That said, I left C for D years ago. I get easy, almost transparent use of C libraries, ability to run with or without GC (`-betterC`), metaprogramming, digit group separators (one of the changes slated for C23), UTF16/32 types, and an amazing standard library. (Full disclosure, much of the std library Phobos is GC dependent but this is being worked on)
Closures: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2737.pdf
Type inference for variable definitions and function returns: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2735.pdf
Type generic programming: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2734.pdf
Defer mechanism: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2589.pdf
What is miss the most: the preprocessor still has no macro that modifies or creates a new macro.It’s good to see that the standard committee is adding these new things that make C easier to use.
It’s been a bit of a struggle to stick just with C, because a lot of people I see teaching/writing modern C, just write C in a cpp file, and cherry pick the c++ features they want.
I wonder how many standards we would have to go through, before the people that are writing C+ (C with some C++ but no classes, RAII, etc) to be converted back to plain old C
Note that this happens to work when the argument's type is int (or anything smaller) only because of default argument promotions. For larger types it will cause undefined behaviour. So, for example, printf("%w8d", 0x1LL) is not legal.
They get promoted to int, and the result overflows.
Still no computed goto?
Some progress on standardizing inline assembler syntax would be nice too.
Or maybe it won't matter anymore because everyone will be using either gcc or clang.
If your allocator can't use the sizing information when free'ing, it can just be a no-op. If it can, it can result in some performance gains.
You also get the bonus the allocator can run stricter consistency checks on the object itself i.e. free(m,size) can ensure that 'm' actually is of the given 'size', or abort the program. This can help find and catch latent bugs.
There's also a middle ground where you get more ILP by assuming the size argument is correct (for performance), and overlap the work of `free`ing memory with a confirmation that the size argument matches malloc's internal metadata.
It's valuable but let's not confuse it with defer which allows a great deal of safety without requiring exceptions.