SYNOPSIS: unary-operator: . identifier DESCRIPTION: - It is not an lvalue. - This means sizeof() and _Lengthof() cannot be applied to them. - This prevents ambiguity with a designator in an initializer-list within a nested braced-initializer. - The type of a .identifier is always an incomplete type. - This prevents circular dependencies involving sizeof() or _Lengthof(). - Shadowing rules apply. - This prevents ambiguity. EXAMPLES: - Valid examples (libc): int strncmp(const char s1[.n], const char s2[.n], size_t n); int cacheflush(void addr[.nbytes], int nbytes, int cache); long mbind(void addr[.len], unsigned long len, int mode, const unsigned long nodemask[(.maxnode + ULONG_WIDTH ‐ 1) / ULONG_WIDTH], unsigned long maxnode, unsigned int flags); void * bsearch(const void key[.size], const void base[.size * .nmemb], size_t nmemb, size_t size, int (*compar)(const void [.size], const void [.size])); - Valid examples (my own): void ustr2str(char dst[restrict .len + 1], const char src[restrict .len], size_t len); char * stpecpy(char dst[.end - .dst + 1], char *restrict src, char end[1]); - Valid examples (from this thread): - struct s { int a; }; void f(int a, int b[((struct s) { .a = 1 }).a]); Explanation: - Because of shadowing rules, .a=1 refers to the struct member. - Also, if .a referred to the parameter, it would be an rvalue, so it wouldn't be valid to assign to it. - (...).a refers to the struct member too, since otherwise an rvalue is not expected there. - void foo(struct bar { int x; char c[.x] } a, int x); Explanation: - Because of shadowing rules, [.x] refers to the struct member. - struct bar { int y; }; void foo(char p[((struct bar){ .y = .x }).y], int x); Explanation: - .x unambiguously refers to the parameter. - Undefined behavior: - struct bar { int y; }; void foo(char p[((struct bar){ .y = .y }).y], int y); Explanation: - Because of shadowing rules, =.y refers to the struct member. - .y=.y means initialize the member with itself (uninitialized use). - (...).y refers to the struct member, since otherwise an rvalue is not expected there. - Constraint violations: - void foo(char (*a)[sizeof *.b], char (*b)[sizeof *.a]); Explanation: - sizeof(*.b): Cannot get size of incomplete type. - sizeof(*.a): Cannot get size of incomplete type. - void f(size_t s, int a[sizeof(1) = 1]); Explanation: - Cannot assign to rvalue. - void f(size_t s, int a[.s = 1]); Explanation: - Cannot assign to rvalue. - void f(size_t s, int a[sizeof(.s)]); Explanation: - sizeof(.s): Cannot get size of incomplete type. Does this idea make sense to you? Cheers, Alex --