Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.std.c > #1760 > unrolled thread
| Started by | Keith Thompson <kst-u@mib.org> |
|---|---|
| First post | 2012-12-18 17:28 -0800 |
| Last post | 2012-12-21 08:55 -0800 |
| Articles | 7 — 3 participants |
Back to article view | Back to comp.std.c
What does it mean to evaluate a VLA? Keith Thompson <kst-u@mib.org> - 2012-12-18 17:28 -0800
Re: What does it mean to evaluate a VLA? Shao Miller <sha0.miller@gmail.com> - 2012-12-18 21:09 -0500
Re: What does it mean to evaluate a VLA? Shao Miller <sha0.miller@gmail.com> - 2012-12-20 03:52 -0500
Re: What does it mean to evaluate a VLA? Shao Miller <sha0.miller@gmail.com> - 2012-12-20 04:08 -0500
Re: What does it mean to evaluate a VLA? Tim Rentsch <txr@alumni.caltech.edu> - 2012-12-20 20:43 -0800
Re: What does it mean to evaluate a VLA? Shao Miller <sha0.miller@gmail.com> - 2012-12-21 05:01 -0500
Re: What does it mean to evaluate a VLA? Tim Rentsch <txr@alumni.caltech.edu> - 2012-12-21 08:55 -0800
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2012-12-18 17:28 -0800 |
| Subject | What does it mean to evaluate a VLA? |
| Message-ID | <lnr4mmrftq.fsf@nuthaus.mib.org> |
N1370 6.5.3.4p2, discussing the sizeof operator, says:
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.
What does it mean to "evaluate" the operand of sizeof when it's of a
variable length array type?
An example:
int n = 42;
volatile int vla[n];
printf("sizeof vla = %zu\n", sizeof vla);
Without the "volatile", the only thing the compiler *needs* to evaluate
is (probably) the hidden internal variable that records the length of
the VLA. A strict reading of 6.5.3.4p2 implies that it must evaluate
the array expression itself, which presumably requires accessing the
elements of the array (since they're declared volatile). I doubt that
that was intended (or likely even considered, since it's a rather odd
corner case).
Another example:
printf("%zu\n", sizeof (char[printf("Hello, world\n")]));
Here the operand is a parenthesized type name, which must be "evaluated"
-- but as far as I know there's no definition of evaluating a type name.
Clearly we need to evaluate any *expressions* contained within the type
name in order to be able to determine its size, which means that both
printf() calls will be executed.
I suggest that this reflects the intent:
If the operand is an expression of a variable length array type,
the expression is not evaluated, but the result is not an integer
constant expression. If the operand is a parenthesized name of
a variable length array type, any expressions within the type
name are evaluated. Otherwise, the operand is not evaluated
and the result is an integer constant expression.
Note also that this changes the final phrase from "integer constant" to
"integer constant expression"; see my earlier post here:
Message-ID: <lnip8zmud9.fsf@nuthaus.mib.org>
https://groups.google.com/forum/?fromgroups=#!topic/comp.std.c/wLso961KBZI
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [next] | [standalone]
| From | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| Date | 2012-12-18 21:09 -0500 |
| Message-ID | <kar7lo$5dk$1@dont-email.me> |
| In reply to | #1760 |
On 12/18/2012 20:28, Keith Thompson wrote:
> N1370 6.5.3.4p2, discussing the sizeof operator, says:
>
> 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.
>
> What does it mean to "evaluate" the operand of sizeof when it's of a
> variable length array type?
>
I think it means to evaluate it as a void expression, for its side effects.
I would be startled if:
size_t sz = sizeof (func1(), (int[func2()]){0});
didn't evaluate 'func1', which might influence the output of 'func2'.
(Untested.)
> An example:
>
> int n = 42;
> volatile int vla[n];
> printf("sizeof vla = %zu\n", sizeof vla);
>
I think the element type is 'volatile', not the array[C11 6.7.3p9].
It's still interesting that if the "as a void expression" theory above
is correct, "nothing happens" for 'vla' here, because it's an array and
an operand to 'sizeof', so not even a pointer value need be computed
(else 'register' could go wrong).
But there's another situation where evaluation seems to happen despite
apparent suppression:
size_t sz = sizeof *( 0 ? 0 : (int(*)[myfunc()]) 0 );
The ternary's third operand "isn't evaluated," but because its type
needs to be determined, those portions required for that determination
are. In this case, 'myfunc' is called.
I like to imagine that expressions are split into at least "type" and
"value," and evaluation for the determination of one may be separate
from evaluation for purposes of the other. I think the non-VLA 'sizeof'
case suppresses evaluations for value, but doesn't suppress those for type:
size_t sz = sizeof (int[42 ? 1 : 3]);
- Shao Miller
[toc] | [prev] | [next] | [standalone]
| From | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| Date | 2012-12-20 03:52 -0500 |
| Message-ID | <kaujkm$av4$1@dont-email.me> |
| In reply to | #1762 |
On 12/18/2012 21:09, Shao Miller wrote:
>
> I would be startled if:
>
> size_t sz = sizeof (func1(), (int[func2()]){0});
>
> didn't evaluate 'func1', which might influence the output of 'func2'.
> (Untested.)
>
Erm, rather:
size_t sz = sizeof *(int(*)[(func1(), func2())]) 0;
Oops.
- Shao Miller
[toc] | [prev] | [next] | [standalone]
| From | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| Date | 2012-12-20 04:08 -0500 |
| Message-ID | <kaukj4$ftf$1@dont-email.me> |
| In reply to | #1765 |
On 12/20/2012 03:52, Shao Miller wrote:
> On 12/18/2012 21:09, Shao Miller wrote:
>>
>> I would be startled if:
>>
>> size_t sz = sizeof (func1(), (int[func2()]){0});
>>
>> didn't evaluate 'func1', which might influence the output of 'func2'.
>> (Untested.)
>>
>
> Erm, rather:
>
> size_t sz = sizeof *(int(*)[(func1(), func2())]) 0;
>
> Oops.
>
Erm, that one has undefined behaviour for dereferencing a null pointer.
So rather:
int foo[MORE_THAN_FUNC2_RETURNS];
size_t sz = sizeof *(func1(), (int(*)[func2()]) &foo);
Sorry about that. Hopefully the point about being "startled" is clear. :)
- Shao Miller
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2012-12-20 20:43 -0800 |
| Message-ID | <kfnpq24816y.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #1760 |
Keith Thompson <kst-u@mib.org> writes:
> N1370 6.5.3.4p2, discussing the sizeof operator, says:
>
> 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.
>
> What does it mean to "evaluate" the operand of sizeof when it's of a
> variable length array type?
The address is computed (including evaluating any subexpressions
necessary to do that, which could include evaluating an array
declarator dimension expression in a type-name). Since the array
is an operand of sizeof, nothing further is done with the
computed address.
> An example:
>
> int n = 42;
> volatile int vla[n];
> printf("sizeof vla = %zu\n", sizeof vla);
>
> Without the "volatile", the only thing the compiler *needs* to evaluate
> is (probably) the hidden internal variable that records the length of
> the VLA. A strict reading of 6.5.3.4p2 implies that it must evaluate
> the array expression itself, which presumably requires accessing the
> elements of the array (since they're declared volatile). I doubt that
> that was intended (or likely even considered, since it's a rather odd
> corner case).
The presence of volatile doesn't change anything, even if somehow
it applied to the array itself rather than just the array's
elements. Direct operands of sizeof are not subject to lvalue
conversion, and therefore do not access objects (there could be
object access in a subexpression, but in that case there would
be a conversion from an array type to a pointer type, just like
ordinary code, so nothing unusual happens there). Hence volatile
makes no difference.
> Another example:
>
> printf("%zu\n", sizeof (char[printf("Hello, world\n")]));
>
> Here the operand is a parenthesized type name, which must be "evaluated"
> -- but as far as I know there's no definition of evaluating a type name.
> Clearly we need to evaluate any *expressions* contained within the type
> name in order to be able to determine its size, which means that both
> printf() calls will be executed.
Right. AFAIK there is no text in the Standard that says clearly
and unambiguously that type-names in expressions must be evaluated
when the containing expression is. About the best I could find is
reasoning that such a type-name is an operand of its larger
expression, and value computations of operands must precede the
value computation of the containing expression. It seems clear
there is an expectation that array declarators in such type-names
be evaluated when their containing expression is, but I don't
think that any text in the Standard says that directly.
> I suggest that this reflects the intent:
>
> If the operand is an expression of a variable length array type,
> the expression is not evaluated, but the result is not an integer
> constant expression. If the operand is a parenthesized name of
> a variable length array type, any expressions within the type
> name are evaluated. Otherwise, the operand is not evaluated
> and the result is an integer constant expression.
>
> Note also that this changes the final phrase from "integer constant" to
> "integer constant expression"; see my earlier post here:
> Message-ID: <lnip8zmud9.fsf@nuthaus.mib.org>
> https://groups.google.com/forum/?fromgroups=#!topic/comp.std.c/wLso961KBZI
The key issue here is evaluation of expressions in type-names.
The description of sizeof is not the right place to give that;
probably it should go either in the section on Array Declarators
or the section on Type Names (whatever those numbers are). Once
it is established that expressions in type-names must be evaluated
as part of evaluating their containing expression, which I believe
is always true, eg, in casts, then the stuff in sizeof is okay.
(I have responded separately on the point about integer constant
expressions. In any case I think that's irrelevant to the main
issue here, which is a need to be more explicit about type-names
being evaluated whenever their containing expressions are.)
[toc] | [prev] | [next] | [standalone]
| From | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| Date | 2012-12-21 05:01 -0500 |
| Message-ID | <kb1c2p$iru$1@dont-email.me> |
| In reply to | #1774 |
On 12/20/2012 23:43, Tim Rentsch wrote:
> Keith Thompson <kst-u@mib.org> writes:
>
>> N1370 6.5.3.4p2, discussing the sizeof operator, says:
>>
>> 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.
>>
>> What does it mean to "evaluate" the operand of sizeof when it's of a
>> variable length array type?
>
> The address is computed (including evaluating any subexpressions
> necessary to do that, which could include evaluating an array
> declarator dimension expression in a type-name). Since the array
> is an operand of sizeof, nothing further is done with the
> computed address.
>
Mentioned elsethread is the 'register' case. I can't think of why the
address would ever need to be computed.
>> An example:
>>
>> int n = 42;
>> volatile int vla[n];
>> printf("sizeof vla = %zu\n", sizeof vla);
>>
>> [...]
>
> [...]
>
>> Another example:
>>
>> printf("%zu\n", sizeof (char[printf("Hello, world\n")]));
>>
>> Here the operand is a parenthesized type name, which must be "evaluated"
>> -- but as far as I know there's no definition of evaluating a type name.
>> Clearly we need to evaluate any *expressions* contained within the type
>> name in order to be able to determine its size, which means that both
>> printf() calls will be executed.
>
> Right. AFAIK there is no text in the Standard that says clearly
> and unambiguously that type-names in expressions must be evaluated
> when the containing expression is. About the best I could find is
> reasoning that such a type-name is an operand of its larger
> expression, and value computations of operands must precede the
> value computation of the containing expression. It seems clear
> there is an expectation that array declarators in such type-names
> be evaluated when their containing expression is, but I don't
> think that any text in the Standard says that directly.
>
> [...]
> The key issue here is evaluation of expressions in type-names.
> The description of sizeof is not the right place to give that;
> probably it should go either in the section on Array Declarators
> or the section on Type Names (whatever those numbers are). Once
> it is established that expressions in type-names must be evaluated
> as part of evaluating their containing expression, which I believe
> is always true, eg, in casts, then the stuff in sizeof is okay.
>
> [...]
>
C was so much simpler before VLAs... :)
If expressions in type-names contribute to the size of the type, how can
they not be evaluated? Whether they're evaluated at translation-time or
at run-time would seem to depend on what contributes to the size, with
VLAs being the only run-time case.
Not that anyone asked, but personally, I find the Standard to be
straight-forward on this matter. Having said that, perhaps this would
be clearer (opinions?):
"The sizeof operator yields the size (in bytes) of its operand, which
may be an expression or the parenthesized name of a type. The size is
determined from the type of the operand. The result is an integer. If
the type of the operand is a variable length array type, the operand is
evaluated as a void expression; otherwise, only those sub-expressions of
the operand that are required in order to determine its size are
evaluated and the result is an integer constant."
int foo[42 ? 1 : 3];
- Shao Miller
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2012-12-21 08:55 -0800 |
| Message-ID | <kfn38yz73ar.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #1784 |
Shao Miller <sha0.miller@gmail.com> writes:
> On 12/20/2012 23:43, Tim Rentsch wrote:
>> Keith Thompson <kst-u@mib.org> writes:
>>
>>> N1370 6.5.3.4p2, discussing the sizeof operator, says:
>>>
>>> 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.
>>>
>>> What does it mean to "evaluate" the operand of sizeof when it's of a
>>> variable length array type?
>>
>> The address is computed (including evaluating any subexpressions
>> necessary to do that, which could include evaluating an array
>> declarator dimension expression in a type-name). Since the array
>> is an operand of sizeof, nothing further is done with the
>> computed address.
>
> Mentioned elsethread is the 'register' case. I can't think of
> why the address would ever need to be computed.
It must be computed, in the abstract machine, because that's what
the Standard says will happen. Naturally no computation will
occur during actual execution.
>>> An example:
>>>
>>> int n = 42;
>>> volatile int vla[n];
>>> printf("sizeof vla = %zu\n", sizeof vla);
>>>
>>> [...]
>>
>> [...]
>>
>>> Another example:
>>>
>>> printf("%zu\n", sizeof (char[printf("Hello, world\n")]));
>>>
>>> Here the operand is a parenthesized type name, which must be "evaluated"
>>> -- but as far as I know there's no definition of evaluating a type name.
>>> Clearly we need to evaluate any *expressions* contained within the type
>>> name in order to be able to determine its size, which means that both
>>> printf() calls will be executed.
>>
>> Right. AFAIK there is no text in the Standard that says clearly
>> and unambiguously that type-names in expressions must be evaluated
>> when the containing expression is. About the best I could find is
>> reasoning that such a type-name is an operand of its larger
>> expression, and value computations of operands must precede the
>> value computation of the containing expression. It seems clear
>> there is an expectation that array declarators in such type-names
>> be evaluated when their containing expression is, but I don't
>> think that any text in the Standard says that directly.
>>
>> [...]
>> The key issue here is evaluation of expressions in type-names.
>> The description of sizeof is not the right place to give that;
>> probably it should go either in the section on Array Declarators
>> or the section on Type Names (whatever those numbers are). Once
>> it is established that expressions in type-names must be evaluated
>> as part of evaluating their containing expression, which I believe
>> is always true, eg, in casts, then the stuff in sizeof is okay.
>>
>> [...]
>
> C was so much simpler before VLAs... :)
>
> If expressions in type-names contribute to the size of the type, how
> can they not be evaluated? [snip elaboration and unrelated]
Obviously, they must be. And since they must be, the Standard
ought to express that such evaluations are to take place.
There is no confusion about what has to happen - only a complaint
that it is not described adequately.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.std.c
csiph-web