
A little-known C feature: Static array indices in parameter declarations (2013) - fanf2
https://hamberg.no/erlend/posts/2013-02-18-static-array-indices.html
======
tptacek
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.

~~~
robertelder
If you like that, there is yet another seldom seen feature of c99, the use of
' __ _' in an array declarator:

    
    
        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.html](http://port70.net/~nsz/c/c99/n1256.html)

Edit: I can't figure out how to escapse an asterisk, so the above might not
read correctly but I tried.

~~~
shaklee3
What's the point of this? It seems like it's the same as not including the
asterisk in the first place.

~~~
xelxebar
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.

~~~
anilakar
If I understood correctly, this will be removed in C2x.

------
lenary
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.

------
adrusi
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:

    
    
        #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;
        }

~~~
eliasdaler
That's because the compiler would have to track at compile time which value
the "foo" has.

~~~
astrobe_
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.

------
vortico
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.

~~~
DSMan195276
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.

~~~
1over137
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.

~~~
DSMan195276
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.

------
Koshkin
> _nice_

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...

------
will4274
C's "static" \- a Short Token who's meaning is Always Taken In Context.

------
Animats
I once proposed to extend that to allow array size checking.[1]

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](http://www.animats.com/papers/languages/safearraysforc43.pdf)

~~~
pjmlp
Hardware solutions like Solaris with SPARC ADI are the only workable way, if
ISO C is not willing to actually change the language.

However the other CPU vendors and OS developers don't seem to be in a hurry to
provide similar security support.

~~~
caf
There's also Intel MPX: [https://intel-mpx.github.io/design/](https://intel-
mpx.github.io/design/)

~~~
pjmlp
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.

------
shmerl
I wouldn't call another overloading of static keyword, a nice feature. Useful
may be, but ugly given how overused the keyword is.

------
legohead
am I the only one that loves C but hates C99?

~~~
geezerjay
It's hard to love C over C99 with its declaration before statements rule.

