There is something personally poetic (is that a thing? it's poetic to me, but maybe not to you?) about a C feature I was unaware of despite working in the language for 25 years being yet another way in which the keyword "static" is overloaded.
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.
It seems this only really matters in function prototype declarations that contain multidimensional arrays. Compare:
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 know. I mean if they differentiated keywords like static with _ (and didn't allow it as a variable prefix) then they could have an infinite number on non-clashing language keywords...
That's exactly how it works for all new (from C99 onward) keywords.
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.
They are likely to remove this in the next C standard (or may have already), because a declaration with a static size is “compatible” with a declaration with no static size, and thus you can get unsoundness.
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.
Try as I might I can't get gcc to produce warnings for this (invocation: gcc --std=c99 -Wall -Werror -Wpedantic -Wnonnull). I can get clang to do so however.
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:
That's what I was afraid of, the feature is "incomplete" in my eyes, because one would expect the compiler to be "smart enough" to catch this case. A feature such like this that has an unclear perimeter is of little use.
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.
Seems cool, but how is useful in practice? In 15 years I've never written a C function taking a fixed array size at all. I always write my functions with a dynamic size argument like
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.
I would agree. IMO, I would argue that if you are in that situation, you should just wrap the array in a `struct`. It will work the same way, but now nobody can get the size wrong - the `struct` will always have an array of the correct length inside it. And as a bonus you can give it a good name.
I like using pointer-to-array types for this purpose as (like an array in struct) the array's length is encoded in the type, and thus likewise allows the compiler to warn if an incompatible array is provided.
e.g.
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.
This is a fantastic technique that didn't occur to me for an embedded project that I was developing in C and where passing arrays of known size was a frequent thing. Also it was desirable to save space by avoiding the padding that a "array+size" struct would contain.
But remember structure padding, which the compiler is free to add in the middle (and end) of a struct (though there are pragmas and/or attributes to pack structs). IOW, an array and a struct are not necessarily the same in memory.
That's completely true, however in practice any extra padding shouldn't matter unless you're trying to do some funny buisness or are severly memory constrained. If all you really needed was a fixed-sized array, then it should work exactly the same, even if it technically uses a byte or two more. (Edit: And of course, while I think you already know this, the compiler can't add padding inside the array, so the array it self will still be exactly the same memory-wise).
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.
The `n` may be any assignment-expression, and as a result values like `n` are appear to be allowed by the standard.
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.
Not only do the opportunities to use it seem to be limited, but the opportunities for the compiler to statically check that the constraint is respected seem limited, both in the case of the caller and in the implementation of the function.
This is not primary about static checking. This is mostly a guarantee to the implementation so it has information at the target function so it can generate better code without having to resort to derivations or complex data flows (to optimize, basically).
If you have ever written a function that accepts a pointer to a single value as an argument, with null pointer not being valid input, then declaring it as a static 1-element array should make things just a little bit better (mainly because the compiler can assume no null).
The clang nullability annotations can be used in C/C++ as extensions: https://clang.llvm.org/docs/AttributeReference.html#nullabil... You could then conditionally define your NOTNULL using them or not. The compiler will then complain about incorrect usage.
You didn't read the article it seems static in this context doesn't mean a fixed array size it means at least as many as indicated. Take for example strlen(const char *src) could be strlen(const char src[static 1])
The standard says "If the expression is a constant expression, it shall have a value greater than zero." Clang gives me a warning that "static 0" has no effect. NULL is valid as a pointer to a 0-length array, so that makes sense that it wouldn't function as a non-NULL assertion.
Here's an example of "use in anger", https://gitlab.com/jjg/lcrp/blob/master/lcrp.c#L159 -- the algorithm used needs the array to have at least 3 elements, generally there will be more. It seems useful that there is a mechanism to warn the future me that this limit should be observed.
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...
Intel has deprecated MPX and will remove it from newer CPU generations.
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.
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.