185

While browsing some source code I came across a function like this:

void someFunction(char someArray[static 100])
{
    // do something cool here
}

With some experimentation it appears other qualifiers may appear there too:

void someFunction(char someArray[const])
{
    // do something cool here
}

It appears that qualifiers are only allowed inside the [ ] when the array is declared as a parameter of a function. What do these do? Why is it different for function parameters?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
dreamlax
  • 93,976
  • 29
  • 161
  • 209

1 Answers1

161

The first declaration tells the compiler that someArray is at least 100 elements long. This can be used for optimizations. For example, it also means that someArray is never NULL.

Note that the C Standard does not require the compiler to diagnose when a call to the function does not meet these requirements (i.e., it is silent undefined behaviour).

The second declaration simply declares someArray (not someArray's elements!) as const, i.e., you can not write someArray=someOtherArray. It is the same as if the parameter were char * const someArray.

This syntax is only usable within the innermost [] of an array declarator in a function parameter list; it would not make sense in other contexts.

The Standard text, which covers both of the above cases, is in C11 6.7.6.3/7 (was 6.7.5.3/7 in C99):

A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.

Todd Lehman
  • 2,880
  • 1
  • 26
  • 32
Nordic Mainframe
  • 28,058
  • 10
  • 66
  • 83
  • 43
    On this topic: I wonder if it should be considered preferable to use `int foo(struct bar [static 1]);` instead of `int foo(struct bar *);` as the signature for functions which do not accept NULL pointers. (I know gcc has an alternate nonstandard syntax to flag such functions so that the compiler can give warnings..) – R.. GitHub STOP HELPING ICE Aug 07 '10 at 12:24
  • 4
    I've just checked gcc and clang and neither assume that someArray is always non null when I ask them to compare against 0. Also I struggle to find the exact clause in C99 which defines it. There's a note in 6.7.5.3-21 which mentions the intended meaning and that's it. I doubt that we can rely on this. Furthermore, all this is not part of the function signature, so there not much that we enforce through it. – Nordic Mainframe Aug 07 '10 at 12:42
  • 7
    That link appears to have rotten away, is this what it was pointing to? http://pic.dhe.ibm.com/infocenter/zos/v1r12/index.jsp?topic=%2Fcom.ibm.zos.r12.cbclx01%2Fparam_decl.htm – Ross Aiken Oct 24 '13 at 17:44
  • If I do `func(int a[static 4][6])` the static can only be declared within the first brackets. What if I do this `func(int (*a)[static 6])` what will this do? Allow me to prefetch the first 6 values of the first row? And finally what about `func(int *a[static 6])`? – user10607 Oct 31 '14 at 13:43
  • 20
    @NordicMainframe: It's been some time, but the current version of `clang` now correctly warns when you attempt to pass a known-NULL argument to a function with a `[static 1]` parameter declaration. – dreamlax Dec 28 '14 at 00:56
  • 1
    Can anyone provide a minimal example of an optimization that could be or is done by compilers when `static` is present but not without? – Ciro Santilli OurBigBook.com May 10 '16 at 20:26
  • 3
    @CiroSantilli巴拿馬文件六四事件法轮功 `if (!someArray) { somecode... }` could be removed – M.M May 10 '16 at 21:12
  • @dreamlax That is certainly not intended or guaranteed by the standard. So this way you are relaying on specific implementation behavior which may not be supported by different compilers. And that's logical by the fact that `int foo(struct bar *)` and `int foo(struct bar[static 1])` have the exact same type. – AnArrayOfFunctions Jun 12 '16 at 14:24
  • @Nordic Mainframe You are incorrect - `char someArray[const]` is not the same as `char (* const someArray)[]`. No-matter the new extension added, still all parameters declared as "array of type" are adjusted to "pointer to type". Which means that `someArray` if of type `char *const` instead. – AnArrayOfFunctions Jun 12 '16 at 14:31
  • @CisNOTthatGOODbutISOisTHATBAD The compiler is allowed to use the additional information to perform additional diagnosis (for example, report if a null pointer is passed, as R.. suggests). Can you clarify what you mean in that comment – M.M Jun 12 '16 at 20:55
  • @CisNOTthatGOODbutISOisTHATBAD sorry, that `char (* const someArray)[]` was my edit. Will fix – M.M Jun 12 '16 at 20:55
  • @CisNOTthatGOODbutISOisTHATBAD: I know that issuing a diagnostic is not required by the standard. There are **lots** of warnings (or diagnostics if you prefer) issued by compilers that are not required by the standard. What's your point? – dreamlax Jun 13 '16 at 00:02
  • My point is to not rely on unintended features as at certain point they may betray you. It's ok I guess for the compiler to issue a warning when it sees obvious violation but you mustn't rely on this behavior in the case. Image a scenario where only your function declaration is visible and you have missed to include the static specifier inside the array parameter declarator in it (which you have supposedly done in its definition later). – AnArrayOfFunctions Jun 13 '16 at 21:43
  • Maybe if the compiler is smart enough it could save you from this situation either (warning your later in the function definition) but what if the function definition isn't available - the static keyword inside the array declarator isn't required to be part of the function type! - you won't get a nice warning then, your code will silently compile and it'll possibly not work correctly after if you were relaying on such warnings to test it. – AnArrayOfFunctions Jun 13 '16 at 21:43
  • _... shall provide access to the **first element of an array with** at least as many elements as specified by the size expression._ So if I write `void someFunction(char someArray[static 100])`, shouldn't `someArray` be guaranteed to gave at least 1 + 100 = 101 elements? – nalzok Aug 27 '17 at 13:30
  • @nalzok Unfortunately not. `char someArray[static 100]` is still an array of 100 elements, whose first element is `someArray[0]` and whose last element is `someArray[99]`. Your confusion may have arisen from the "provide access to" language, possibly inspired by the confusion of arrays and pointers (not quite equivalence, as seen elsewhere on this site): `someArray[0]` == `*(someArray + 0)` == `*someArray`. – michaelb958--GoFundMonica Jun 09 '18 at 10:38
  • *The second declaration simply declares `someArray` (not `someArray`'s elements!) as const, i.e. you can not write `someArray=someOtherArray`* -- could you ever write that, e.g. `foo(char a[]){...a=b;...}`? – tevemadar Nov 14 '18 at 14:50
  • What if a library header that I need to include in a C++ source file declares arrays using the `static` qualifier? Is this allowed by the C++ standard or a gnu extension? – droptop Apr 24 '23 at 16:09