4 ms·
C99 also lets you do this: void foo(size_t elem_count, int elems[elem_count]); Unfortunately this constraints the argument order. C23 fixes that with someth
by TazeTSchnitzel 3y ago
C99 also lets you do this:
void foo(size_t elem_count, int elems[elem_count]);
Unfortunately this constraints the argument order. C23 fixes that with something like this:
void foo(size_t elem_count; int elems[elem_count], elem_count);
(Might be slightly wrong, going from memory.)
- shadowgovt 3y ago> Unfortunately this constraints the argument order In both C and C++, it drives me absolutely bonkers that declaration order matters so much. Point of personal preference, but they're the last languages I use with any regularity where you can't just reference a symbol that will be declared later in the file. In this case, the compiler should be able to figure it out without any of that hinting; the scope of potential valid bindings is in the parentheses. It's a very constrained scope!
- saurik 3y agoRequiring things be defined in the right order is a bit annoying, as the computer can surely figure it out... but a lot of us are working with really large codebases that are very slow to compile and alleviating the compiler from having to know the entire file--or in some cases entire modules... madness!!--before being able to understand what any of it means really helps.
- shadowgovt 3y agoIf compilation speed is an issue, you're already sunk in C and C++ because the #include evaluation rules leave very little room to optimize the massive redundancy of computing headers over and over (and every header includes all its headers, and etc).
- uecker 3y agoIn C headers are not a problem. They are simple and effective. C++ made the mistake of putting implementations into headers for generic programming.
- TazeTSchnitzel 3y agoC can have the same problem, it has inline functions.
- uecker 3y agoSure, you could also put a lot of complicated macros into headers. But in practice it is not a problem because this is not how you would do it in C. But in C++ you put the definition of a class into the header. Also templates basically have to exist in headers. So it is normal for C++ code to have a lot of code in headers.
- akkartik 3y agoYou're basically saying pooling code between a large group might be worthwhile even if it requires you to take on a lot of book-keeping the computer could in principle help with. I don't think I've seen anyone else put it this way before. Then again, we have so much compute going to LLMs lately, I wonder if we need to revisit our assumptions about how much hardware we have available for compilation. What might a language look like with the assumption we can spread LLM-training levels of hardware among everyone working on a large codebase? Or a compiler that can consult some sort of ML-based cache for reordering decisions? There's a new space of options opening up here.
- mananaysiempre 3y agoC23 did not get around to introducing this kind of forward declaration (and, although GCC has had them for a long time, Clang has not implemented that extension either). I think I remember Gustedt (the chair for C11 and C17) openly advocating against the ages-old practice[1] of putting lengths after pointers, I suspect in part because of this problem, and Meneide (the current one) also puts lengths first in his proposed encoding APIs. In any case, the proposal[2] (ETA: by Martin Uecker, who’s also spoken up both in the linked thread and here) is still under consideration, it just didn’t get into C23. [1] With main() being the exception. [2] Latest version being https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3121.pdf https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3121.pdf.
- uecker 3y agoWG14 can still vote it into C23.
- mananaysiempre 3y agoOh. With all the talk about national body comments I thought a freeze of some sort was already in effect. (Which did make the “nope“ paper on integer constant expressions[1] from Clang more than a bit surprising.) Thanks for the correction! [1] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3125.pdf https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3125.pdf
- uecker 3y agoThe freeze is in effect, but issues can still be addressed with NB comments. There was a NB related to this topic and WG14 asked me to create a new revision of this paper.
- uecker 3y agoYes, and with pointer-to-array syntax the bounds checking already works today: https://godbolt.org/z/oc6MTWjYd https://godbolt.org/z/oc6MTWjYd For your syntax we will probably just also add it is an option.
- mananaysiempre 3y agoOne potential difference is variance: AFAIU, if void f(char (*pa)[7]); void g(int x, char (*pa)[x]); void h(int x, char p[static x]); char a[10]; then f(&a) is a constraint violation, and I believe g(7,&a) might actually be UB, whereas h(7,a) is fine. On the other hand, in the latter case void h(int x, char p[static x]) { p = (char *)&x; } is legal, so extending that with bounds checks is also not without its problems.
- uecker 3y agog is UB which is why one can use it easily for checking. h is fine because a is larger than 7. If it were smaller the call could be diagnosed. If you overwrite the pointer inside the function, then the bounds will be lost. (which is different to pa = ... where the bounds still need to match).
- olliej 3y agoThis RFC recognizes that, and does not require additional annotation. It's important to recognize that in plain C the above is simply an aid to someone looking at the header and is no different from void foo(size_t elem_count, int elems[]); As such int j; foo(20, &j); is fine. Under this RFC this is an error and the call site would trap at runtime (if not picked up a compile time). The RFC also comments on (and handles) void foo(int elems[] __counted_by(elem_count), size_t elem_count); Look for references to "delayed parsing". It also handles similar in structs.
- uecker 3y agoWhile most C compilers ignore this the size in C can definitely be used for checking and this is intended, e.g. see the C2X charter: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2086.htm https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2086.htm And compilers do this already to some degree: https://godbolt.org/z/c7xdazKrd https://godbolt.org/z/c7xdazKrd
- olliej 3y agoThe moment the size isn't trivially available the warnings cease. I was using that example just to keep the code brief. This is a problem because it's trivially easy to have code along the lines of void foo(int size, int buffer[size]) { ... int new_base = some_math; int new_size = some_other_math; foo(new_size, buffer+new_base); ... } That computes the size or base incorrectly, and the compiler will do nothing to stop you walking off the ends. Obviously this RFC just uses the existing syntax if it's there and doesn't need explicit annotations, but the existing syntax requires the size parameter first which many APIs don't have. gcc has an extension to pre-declare a parameter name and type but you can't just use macros to make that work in other or older compilers. They also don't support sizes that aren't just a direct reference to a parameter (e.g. you can't make void some_matrix_func(int size, float matrix[size*size])).
- uecker 3y agoThat the size is information is used more for checking is generally ongoing work. Inside a function it can be propagated by the compiler. The old GCC extension can also be hidden behind a macro, so this is backwards compatible: void foo(HIDE(int x;) char buf[HIDE(x)], int x);