2

A simple question: is variably-modified type a VLA (variable length array) only?

C11, 6.10.8.3 Conditional feature macros, 1 (emphasis added):

__STDC_NO_VLA__ The integer constant 1, intended to indicate that the implementation does not support variable length arrays or variably modified types.

Does it mean that there is a variably-modified type, other than VLA? Any examples?

What is the relationship between "variably modified type" and "variable length array"?


Extra: the definition of "variable length array" depends on the definition of "known constant size":

If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.

However, the definition of "known constant size" depends on the definition of "variable length array":

A type has known constant size if the type is not incomplete and is not a variable length array type.

A bit confused.

Related DR: http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_312.htm.

pmor
  • 5,392
  • 4
  • 17
  • 36
  • 1
    The “extra” should be a separate question if it isn’t directly related. The type that has to have known constant size is the *element* type, by the way, so the mutual reference isn’t an issue for as long as there’s an eventual non-array type in an array of arrays of arrays of (…) of something. – Ry- Mar 30 '22 at 22:42
  • 2
    6.7.6 p3 of the C11 working draft: *A full declarator is a declarator that is not part of another declarator. The end of a full declarator is a sequence point. **If, in the nested sequence of declarators in a full declarator, there is a declarator specifying a variable length array type, the type specified by the full declarator is said to be variably modified .** Furthermore, any type derived by declarator type derivation from a variably modified type is itself variably modified* – Christian Gibbons Mar 30 '22 at 22:46
  • 1
    The recursion in the circular definitions of "known constant size" and "variable length array type" ends when you get to a type that isn't an array at all. Then it has a known constant type if it's not incomplete. – Barmar Mar 30 '22 at 22:49
  • @Barmar Thanks. To precise: known constant **size** (not type). – pmor Mar 30 '22 at 22:52
  • @ChristianGibbons Indeed! I've searched the definition of "variably modified type" w/o success because there is "is said to be variably modified". Could you provide an example of a full declarator, which is variably modified? – pmor Mar 30 '22 at 22:57
  • I think every VLA infers a VMT (which should be the type of the VLA at runtime). Example of a VMT other than of a VLA : `struct { unsigned x : n; }` (where `n` is to be evaluated as integer at runtime). – user51187286016 Mar 30 '22 at 22:59
  • @user51187286016 If VMT depends on VLA, then why "does not support variable length arrays **or** variably modified types"? It should be "and" (or "and (as a consequence)"). – pmor Mar 30 '22 at 23:19
  • @pmor (Speculating) I'm blaming it on the vagueness of natural languages. I will abuse the logical operators in the following, but I parsed this as `!support(VLA || VMT)` which should be "de Morgan equivalent" to `!support(VLA) && !support(VMT)`. But this is not the only interpretation of the nat-lang precedence of `not` and `or` (hence poetry). – user51187286016 Mar 30 '22 at 23:30
  • (continued). Yet, because `support(VMT)` implies `support(VLA)` (since variable length arrays must have a type of their own at runtime), results that `!support(VLA)` implies `!support(VMT)` which means that `__STDC_NO_VLA__` set on `1` means also `!support(VMT)`. Again, speculating: I'm no Chomsky. :-) – user51187286016 Mar 30 '22 at 23:38
  • @user51187286016 See comments to Eric Postpischil's answer. Per DeMorgan’s laws "does not support VLAs or VMTs" implies "does not support VLAs and does not support VMTs", where the "VMT depends on VLA" is clearly seen. – pmor Mar 30 '22 at 23:49
  • @pmor I agree with that comment. In that context, not only it **implies**, it is **equivalent**. But --- again --- all the confusion stems from the vague rules of parsing natural language. Written natural language can be still saved by punctuation (compare "not X or Y" to "not X, or Y"); but spoken language is unsalvageable. Is a good thing that we don't have a dramatic genre in programming: prose is good enough. :-) Alright, enough digressing from my part --- sorry if my comments weren't helpful. – user51187286016 Mar 31 '22 at 00:05
  • @user51187286016 Re: "`struct { unsigned x : n; }`": C11: "The expression that specifies the width of a bit-field shall be an **integer constant expression** ...". – pmor Apr 02 '22 at 22:28

2 Answers2

2

Does it mean that there is a variably-modified type, other than VLA? Any examples?

According to the C Standard (6.7.6 Declarators)

3 A full declarator is a declarator that is not part of another declarator. If, in the nested sequence of declarators in a full declarator, there is a declarator specifying a variable length array type, the type specified by the full declarator is said to be variably modified. Furthermore, any type derived by declarator type derivation from a variably modified type is itself variably modified.

Here is a demonstration program

#include <stdio.h>

int main( void )
{
    for ( size_t n = 1; n < 10; n++ )
    {
        typedef int ( *Ptr )[n];
        Ptr p;

        printf( "sizeof( *p ) = %zu\n", sizeof( *p ) );
    }
}

The program output is

sizeof( *p ) = 4
sizeof( *p ) = 8
sizeof( *p ) = 12
sizeof( *p ) = 16
sizeof( *p ) = 20
sizeof( *p ) = 24
sizeof( *p ) = 28
sizeof( *p ) = 32
sizeof( *p ) = 36

In this program the pointer type Ptr defined like int( * )[n] is a variably modified type.

This quote

A type has known constant size if the type is not incomplete and is not a variable length array type.

means that the sizeof operator for such types is evaluated at compile-time opposite to the evaluation at run-time for variable length array types and the size of such a type is not changed during the program execution.

The quote has a different meaning relative to the quote below

If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.

that says about how distinguish a declaration of a variable length array from a declaration of a non-variable length array.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • The fact that _pointer_ `int( * )[n]` is a variably modified type looks surprising. – pmor Mar 30 '22 at 23:06
  • @pmor It follows from the quote. – Vlad from Moscow Mar 30 '22 at 23:07
  • Where does C standard require to evaluate `size_expression` for `int(*)[]`? – pmor Mar 31 '22 at 17:58
  • @pmor In the quote there is written about a nested sub-declarator that represents a variable length array type. – Vlad from Moscow Mar 31 '22 at 19:32
  • Hm. Can you elaborate please? There is "otherwise, each time it is evaluated, ...". OK, but is there a clear and complete set of rules answering "when the size expression is required to be evaluated" question? – pmor Mar 31 '22 at 21:50
  • @pmor If I have understood your question correctly then in the C Standard there is written "If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant." Also see the demonstration program in my answer. – Vlad from Moscow Mar 31 '22 at 21:53
  • Yes, for `sizeof` it is clear, thanks. The demo program is illustrative. However, for `int(*)[f1()]` it is not yet clear for me where it is required for `f1()` to be evaluated. Yes, the VMT is derived from VLA. However, does it mean that all the rules for evaluation of the size expression for VLA are applicable for VMT as well? How can you comment? – pmor Mar 31 '22 at 22:21
  • @pmor Pointers to objects are always complete types. But a pointer to an incomplete type you may not dereference. In the demonstration program there is a pointer to a variable length array. So when it is dereferenced the size of the pointed array is evaluated. – Vlad from Moscow Mar 31 '22 at 22:24
  • As I understand, the size expression is evaluated at declaration and not at indirection. – pmor Mar 31 '22 at 23:28
1

C 2018 6.7.6 3 says:

If, in the nested sequence of declarators in a full declarator, there is a declarator specifying a variable length array type, the type specified by the full declarator is said to be variably modified. Furthermore, any type derived by declarator type derivation from a variably modified type is itself variably modified.

Therefore int (*)[n], for some non-constant n, is a variably modified type even though it is a pointer. Further, int [3][n] is a variably modified type.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Thanks! Re: "variably modified type even though it is a pointer": indeed, though it may be non-trivial / surprising. – pmor Mar 30 '22 at 23:03
  • If VMT depends on VLA, then why "does not support variable length arrays **or** variably modified types"? It should be "and" (or "and (as a consequence)"). – pmor Mar 30 '22 at 23:18
  • 2
    @pmor: Because of DeMorgan’s laws: “not A and not B” is “not (A or B)”. If an implementation supported variable length arrays but not variably then types, then it would “not support variable length arrays and variably modified types”. – Eric Postpischil Mar 30 '22 at 23:25
  • I've interpreted "does not support VLAs or VMTs" as "does not support VLAs or does not support VMTs" instead of "does not support VLAs and does not support VMTs". – pmor Mar 30 '22 at 23:44
  • Where does C standard require to evaluate `size_expression` for `int(*)[]`? – pmor Mar 31 '22 at 18:10
  • If VMT is derived from VLA, then does it follow that VMT's size expression evaluation rules is the superset of VLA's size expression evaluation rules? – pmor Mar 31 '22 at 19:00
  • Found in WG14/N317: "The array size specified by the variable length array type shall be evaluated at the time the type definition is declared and not at the time it is used as a type specifier in an actual declarator". Rationale: "If the evaluation were to take place each time the typedef name is used, then a single type definition could yield variable length array types involving many different dimension sizes. This possibility seemed to violate the spirit of type definitions and Cray Research decided to force evaluation of the expression at the time the type definition itself is declared". – pmor Apr 05 '22 at 15:27