A little-known C feature: Static array indices in parameter declarations (2013)
hamberg.no
hamberg.no
It's as if they go around looking for places in the grammar they can unambiguously stick "static" and then back-rationalize a meaning for it.
echo 'int my_func(int i, int arr[*]);' > main.c
gcc -c -std=c99 main.c
-- * observe that there are no errors * --
See 6.7.5.2 Array declarators for details
http://port70.net/~nsz/c/c99/n1256.htmlEdit: I can't figure out how to escapse an asterisk, so the above might not read correctly but I tried.
In code blocks *asterisks* don't need any special
escaping as they always show up "as is". int foo(char [][*]);
int bar(char [][]);
The second declaration should give an error.I'm getting this from just reading the spec now, but it looks like the reason has to do with "incomplete" versus "complete" types.
Something like 'int arr[]' is an "incomplete type", i.e. an array of ints with unspecified size. While 'int arr[*]' is a complete type for an array with variable length. I'm guessing that array elements must have a complete type, which is why the above snippet gives an error.
I would think that that's exactly what they do, in order to avoid breaking existing code by introducing any more reserved words.
The actual keywords are defined with a leading underscore and a capital letter. The standard reserves all such identifiers for implementation, and so no valid conforming program should contain any such.
Thus, you get keywords like _Bool and _Complex. And then, to make them look nice, there are headers like <stdbool.h> which basically just do #define bool _Bool etc.
So your compiler should accept (though the semantics of static suggest this program would be wrong):
void foo(int a[static 3]);
void foo(int a[]);
According to the spec, this is fine, but when you come to define the function foo, should it respect the ‘static’ annotation? The spec doesn’t say, and doing static analysis of subsumption for the expressions after ‘static’ is much more complex to keep sound than C prefers in its specification.I didn't expect to get any compiler warnings for code that passes NULL to a [static 1] parameter, so I wasn't surprised when this code compiled silently:
#include <stdio.h>
void end(int foo[static 1]) {
printf("%d\n", *foo);
}
void middle(int *foo) {
end(foo);
}
int main() {
middle(NULL);
return 0;
}
But I was a bit disappointed that the following compiled without warning as well: #include <stdio.h>
void end(int foo[static 1]) {
printf("%d\n", *foo);
}
int main() {
int *foo = NULL;
end(foo);
return 0;
}Well, I guess that this feature has a precise definition in the C spec, but one should note that the purpose half of the warnings the compiler emits (guesstimate) is to mitigate the imperfect knowledge of the C spec. Typical example is operator precedence: who can remember 17 levels of precedence? One can remember the obvious cases, one can remember the less obvious case if one uses them often enough, but anything besides that (and when in doubt when you trying to figure out where a bug comes from), one just says "fack it" and put parenthesis everywhere. Smalltalk, APL, Lisp, Forth were quite right to sacrifice natural expressions notations for something more useful than being kind with beginners. An unnatural but simpler model is better than a natural but more complex model, because programmers are not compilers. This is a fact that compiler/language designers seem to forget sometimes.
So it's not surprise to me that this feature is little known: it's not reliable.
void foo(char *data, int len)
Perhaps cryptography functions with 256-bit outputs might be able to use this, but even when the array size is fixed, most crypto libraries (like OpenSSL) tend to have a size argument anyway, to encourage the caller to think about what they're doing, and for the library to check that 32 bytes are actually available, for example. void foo(char data[static 0], int len)
with 0 or 1 to signal at least zero/one elements are required (for example), and the pointer must be non-null. void wlr_matrix_multiply(float mat[static 9], const float a[static 9],
const float b[static 9]); void foo(const int n, const char data[n])
Is this also valid? void foo(const int n, const char data[static n])I've used this in code compiled with gcc and clang. Both accept this construct, but I'm not sure how effectively any compiler is able to use this information to emit warnings/errors.
void foo(char bar[static 1])
vs void foo(NOTNULL(char* bar))
Though I'm not sure whether this can be expressed as a macro, since you need to remove the "*"? #define NOTNULL
void foo(NOTNULL char *bar)
If you're using Objective-C, then nonnull is your friend.https://news.ycombinator.com/item?id=18787595
The compiler didn't complain when passed a pointer to NULL (ok, not the same as passing NULL.
void f(char (*n)[255]);
char array[6];
f(&array);
warns of "incompatible pointer types passing 'char (* )[6]' to parameter of type 'char (* )[255]'"This won't produce a diagnostic for f(NULL) like "static" does, but does have two properties that might be considered benefits:
1) The length is exact rather than a minimum.
2) The type of "* n" is still char[255], whereas a char[static 255] parameter is still a decayed pointer-to-char. Thus with the former sizeof(* n) behaves as expected inside of "f", yielding 255.
These are true of the array-in-struct method as well.
Thanks for commenting this.
With that, I wouldn't expect that any padding would be added since the array should already have the same alignment as the `struct` anyway - but compilers are known to do weird things from time to time, so it's definitely not impossible.
Ok, so, in addition to ‘static’ meaning either ‘local static’ or ‘private’, turns out we also have ‘at least.’ While I kinda understand the need to overload keywords, this still rubs the wrong way every time I see it. Well, I guess, if this is OK in a natural language (for a word to have several meanings; and in mathematics, too), it must be OK in a programming language...
The trouble with C static array sizes is that the compiler doesn't do much of anything with the information.
[1] http://www.animats.com/papers/languages/safearraysforc43.pdf
However the other CPU vendors and OS developers don't seem to be in a hurry to provide similar security support.
Likewise GCC 9 will be dropping support.
Only ARM and Google (via Android) are currently serious about such kind of feature support, but it will still take a couple of years until it gets widespread support.