Am Donnerstag, dem 23.01.2025 um 20:24 +0000 schrieb Qing Zhao: > > > On Jan 23, 2025, at 13:27, Martin Uecker <uec...@tugraz.at> wrote: > > > > Am Donnerstag, dem 23.01.2025 um 17:39 +0000 schrieb Qing Zhao: > > > > > > > On Jan 22, 2025, at 12:20, Martin Uecker <uec...@tugraz.at> wrote: > > > > > > > > Am Mittwoch, dem 22.01.2025 um 18:11 +0100 schrieb Martin Uecker: > > > > > Am Mittwoch, dem 22.01.2025 um 16:37 +0000 schrieb Qing Zhao: > > > > > > > > > > > > > On Jan 22, 2025, at 11:22, Martin Uecker <uec...@tugraz.at> wrote: > > > > > > > > > > > > > > > > > > > > > Hello Michael, > > > > > > > > > > > > > > Am Mittwoch, dem 22.01.2025 um 16:54 +0100 schrieb Michael Matz: > > > > > > > > On Wed, 22 Jan 2025, Martin Uecker wrote: > > > > > > > > > > > > > > > > > > > So you do not need to look further. But maybe I am > > > > > > > > > > > missing something > > > > > > > > > > > else. > > > > > > > > > > > > > > > > > > > > Like ... > > > > > > > > > > > > > > > > > > > > > > Note further that you may have '{ .y[1][3].z }', which > > > > > > > > > > > > is still not a > > > > > > > > > > > > designation, but an expression under your proposal, > > > > > > > > > > > > whereas > > > > > > > > > > > > '{ .y[1][3].z = 1 }' would remain a designation. This > > > > > > > > > > > > shows that you > > > > > > > > > > > > now need arbitrary look-ahead to disambiguate the two. > > > > > > > > > > > > A Very Bad Idea. > > > > > > > > > > > > > > > > > > > > ... this? > > > > > > > > > > > > > > > > > > In .y[1][3].z after .y you can decide whether y is a member > > > > > > > > > of the > > > > > > > > > struct being initialized. If it is, it is a designator and > > > > > > > > > if not > > > > > > > > > it must be an expression. > > > > > > > > > > > > > > > > If y is not a member it must be an expression, true. But if > > > > > > > > it's a member > > > > > > > > you don't know, it may be a designation or an expression. > > > > > > > > > > > > > > In an initializer I know all the members. > > > > > > > > > > > > I am not familiar with the parser, so, I am a little confused about > > > > > > the following: > > > > > > > > > > > > Suppose we have: > > > > > > > > > > > > struct foo { > > > > > > int z; > > > > > > float f; > > > > > > } > > > > > > > > > > > > struct bar { > > > > > > char *array __attribute__ ((counted_by (.y[1][3].z + 4))); > > > > > > struct foo y[5][10]; > > > > > > } > > > > > > > > > > > > So, in the above, when parsing the above expression inside > > > > > > counted_by, can the > > > > > > current parser be easily to be extended to parse it? > > > > > > > > > > No, I don't think this can be done easily. The issue is that you do > > > > > not know the declaration for y because it hasn't been parsed yet. > > > > > > > > > > If you forward reference some struct member, you have several > > > > > possibilities: > > > > > > > > > > - use it only in limited contexts where you do not need to know > > > > > the type (e.g. this works for goto labels) or for a basic > > > > > counted_by attribute that only takes an identifier as we have it now. > > > > > > > > > > - simply assume it has a certain type (size_t as is proposed in the > > > > > WG14 paper Joseph mentioned) and fail later if it does not. > > > > > > > > > > > > > > > Both options would rule the construct above (but there could be > > > > > workarounds). > > > > > > > > One of the workarounds could be to instead call a function (which could > > > > be inlined later) and that function takes a pointer to the member. > > > > Then it does not need to now anything about any member, e.g.: > > > > > > > > > > > > struct foo { > > > > int z; > > > > float f; > > > > } > > > > > > > > size_t bar_count(struct bar *); > > > > > > > > struct bar { > > > > char *array __attribute__ ((counted_by (bar_count(__self__)))); > > > > struct foo y[5][10]; > > > > } > > > > > > > > size_t bar_count(struct bar *p) > > > > { > > > > return p->y[1][3].z +4; > > > > } > > > > > > > > > > > In this workaround, we also need to introduce a new key word “__self__”, > > > Is this the same as the “__self__” Joseph mentioned in a previous email > > > (I copied Joseph’s word in below for easy reference): > > > > I think it could be same, although Joseph uses it with a member access. > > > > One could also use designator syntax (without __self__) and pass a reference > > to the member only (which also seems appropriate for counted_by). > > > > struct foo { > > int z; > > float f; > > } > > > > size_t bar_count(struct foo (*yp)[5][10]); > > > > struct bar { > > char *array __attribute__ ((counted_by (bar_count(&.y)))); > > struct foo y[5][10]; > > } > > > > size_t bar_count(struct foo (*yp)[5][10]) > > { > > return (*yp)[1][3].z +4; > > } > > > > So, in the above, “bar_count” is still a function call, right? > Instead passing “__self__” to the function “bar_count”, the above > passed a reference to the member (as &.y) to the function “bar_count”.
Yes. Or, as yet another option, you only give it the function as an argument, and it then calls this function with a pointer to the struct. The function then does whatever it wants. struct foo { int z; float f; } size_t bar_count(struct bar *); struct bar { char *array __attribute__ ((counted_by (bar_count))); struct foo y[5][10]; }; size_t bar_count(struct bar *p) { return p->y[1][3].z + 4; } This is also quite nice and similar to how the "cleanup" attribute worsk. The downside is that this all then heavily relies on inlining, and it somehow encourages misuse because programmers might be tempted to put random code into these functions. There is also the option to just have the attribute on the struct and give two arguments, the member to be bounded and the expression: struct bar { char *array; struct foo y[5][10]; } __attribute__ ((counted_by (array, .y[1][3].z + 4))); (with or without __self__) > > > Or something else? Sorry, maybe I did not send an example before. The idea is that if you want to reference y before it is declared, you can not know its type, but you could take its address and convert it to a pointer of the right type. This could be done by passing to a function which takes the type as argument or by immediately casting it. struct foo { int z; float f; } typedef struct foo cnt_t[5][10]; struct bar { char *array [[counted_by (*(cnt_t*)& .y)[1][3].z + 3)]]; struct foo y[5][10]; }; or alternatively with __self__ struct bar { char *array [[counted_by (*(cnt_t*)& __self__.y)[1][3].z + 3)]]; struct foo y[5][10]; }; Looks a bit uglier, but avoids the function call, and should be easy to implement. Martin > > Qing > > > > > Martin > > > > > > > > > > > Thanks a lot for your help. > > > > > > Qing > > > > > > > > > > > > Other alternatives are: > > > > > > > > > > - you have same kind of forward declaration (as we have for > > > > > parameters as GNU extension). In the context of C, this is the > > > > > cleanest solution but either requires forward declaring the > > > > > full struct (which can be done in C23) or new syntax for only > > > > > forward declaring the member. > > > > > > > > A possible C23 workaround could be: > > > > > > > > struct foo { > > > > int z; > > > > float f; > > > > } > > > > > > > > struct bar { > > > > char *array __attribute__ ((counted_by (*))); > > > > // star indicates missing size exppression > > > > struct foo y[5][10]; > > > > } > > > > > > > > struct bar { // redeclare with known size > > > > char *array __attribute__ ((counted_by (.y[1][3].z + 4))); > > > > struct foo y[5][10]; > > > > } > > > > > > > > > > > > Martin > > > > > > > > > > > > > > > > > > - or you use some delayed parsing where you store away the tokens > > > > > and parse it later when all structure members are done. I think > > > > > this is a highly problematic approach for a variety of reasons. > > > > > > > > > > > > > > > Martin > > > > > > > > > > > > > > > > > > > > > > thanks. > > > > > > > > > > > > Qing > > > > > > > > > > > > > > Martin >