Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #76544 > unrolled thread
| Started by | John Bode <jfbode1029@gmail.com> |
|---|---|
| First post | 2015-11-19 11:39 -0800 |
| Last post | 2015-11-21 12:09 -0800 |
| Articles | 20 on this page of 22 — 7 participants |
Back to article view | Back to comp.lang.c
sizeof on an uninitialized pointer to a VLA John Bode <jfbode1029@gmail.com> - 2015-11-19 11:39 -0800
Re: sizeof on an uninitialized pointer to a VLA supercat@casperkitty.com - 2015-11-19 12:09 -0800
Re: sizeof on an uninitialized pointer to a VLA "A. Bolmarcich" <aggedor@earl-grey.cloud9.net> - 2015-11-19 21:40 +0000
Re: sizeof on an uninitialized pointer to a VLA supercat@casperkitty.com - 2015-11-19 13:50 -0800
Re: sizeof on an uninitialized pointer to a VLA James Kuyper <jameskuyper@verizon.net> - 2015-11-19 17:50 -0500
Re: sizeof on an uninitialized pointer to a VLA supercat@casperkitty.com - 2015-11-19 15:31 -0800
Re: sizeof on an uninitialized pointer to a VLA Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-11-20 01:09 +0000
Re: sizeof on an uninitialized pointer to a VLA supercat@casperkitty.com - 2015-11-19 19:10 -0800
Re: sizeof on an uninitialized pointer to a VLA Keith Thompson <kst-u@mib.org> - 2015-11-20 03:52 -0800
Re: sizeof on an uninitialized pointer to a VLA Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-11-20 14:24 +0000
Re: sizeof on an uninitialized pointer to a VLA supercat@casperkitty.com - 2015-11-20 10:25 -0800
Re: sizeof on an uninitialized pointer to a VLA Keith Thompson <kst-u@mib.org> - 2015-11-20 18:29 -0800
Re: sizeof on an uninitialized pointer to a VLA Ian Collins <ian-news@hotmail.com> - 2015-11-21 16:35 +1300
Re: sizeof on an uninitialized pointer to a VLA Keith Thompson <kst-u@mib.org> - 2015-11-20 20:24 -0800
Re: sizeof on an uninitialized pointer to a VLA Ian Collins <ian-news@hotmail.com> - 2015-11-21 17:38 +1300
Re: sizeof on an uninitialized pointer to a VLA Keith Thompson <kst-u@mib.org> - 2015-11-20 21:08 -0800
Re: sizeof on an uninitialized pointer to a VLA Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-11-21 10:46 +0000
Re: sizeof on an uninitialized pointer to a VLA Keith Thompson <kst-u@mib.org> - 2015-11-21 03:26 -0800
Re: sizeof on an uninitialized pointer to a VLA Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-11-21 12:46 +0000
Re: sizeof on an uninitialized pointer to a VLA Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-11-21 14:01 +0000
Re: sizeof on an uninitialized pointer to a VLA supercat@casperkitty.com - 2015-11-21 09:02 -0800
Re: sizeof on an uninitialized pointer to a VLA Keith Thompson <kst-u@mib.org> - 2015-11-21 12:09 -0800
Page 1 of 2 [1] 2 Next page →
| From | John Bode <jfbode1029@gmail.com> |
|---|---|
| Date | 2015-11-19 11:39 -0800 |
| Subject | sizeof on an uninitialized pointer to a VLA |
| Message-ID | <5e03af2c-3c3e-4432-bf5a-000867e5febb@googlegroups.com> |
I've been using the following idiom a lot to dynamically allocate
2D arrays:
T (*arr)[N] = malloc( sizeof *arr * M );
Works great where N is known at compile time. However, I've also been
applying it to VLAs, like so:
size_t rows;
size_t cols;
...
T (*arr)[rows] = malloc( sizeof *arr * cols );
I've never had any issues, but...does this count as undefined behavior?
`sizeof` evaluates the operand when it's a VLA, but what does "evaluate"
mean in this context? Is it trying to dereference the pointer, or is it
simply determining the size of *any* object the pointer may refer to?
I *should* know this, but I don't.
[toc] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-11-19 12:09 -0800 |
| Message-ID | <a9da3c35-3658-4023-9f6a-a8e4e08d0f1b@googlegroups.com> |
| In reply to | #76544 |
On Thursday, November 19, 2015 at 1:39:56 PM UTC-6, John Bode wrote: > T (*arr)[rows] = malloc( sizeof *arr * cols ); Even though the compiler would have no sensible reason to perform an rvalue conversion upon *arr, the Standard would permit it to do so. The fact that the Standard imposes no constraints upon the behavior of code which could legally be compiled in such a way as to perform an rvalue conversion upon an uninitialized pointer means that the Standard would imposes no constraints on the any aspect of the program's behavior in situations where the above code could be reached. I think the Standard is rather silly in this case, since there is *never* any useful efficiency gain from allowing sizeof to evaluate arguments other than those which contribute to the actual size computation. I would guess that the only reason the Standard allows that is that some compiler had that behavior before the Standard was written, come code might have relied upon it, and the Committee didn't want to forbid anything that someone might already be doing. Otherwise the rule makes no sense.
[toc] | [prev] | [next] | [standalone]
| From | "A. Bolmarcich" <aggedor@earl-grey.cloud9.net> |
|---|---|
| Date | 2015-11-19 21:40 +0000 |
| Message-ID | <slrnn4sgdl.107k.aggedor@earl-grey.cloud9.net> |
| In reply to | #76544 |
On 2015-11-19, John Bode <jfbode1029@gmail.com> wrote: > I've been using the following idiom a lot to dynamically allocate > 2D arrays: > > T (*arr)[N] = malloc( sizeof *arr * M ); > > Works great where N is known at compile time. However, I've also been > applying it to VLAs, like so: > > size_t rows; > size_t cols; > ... > T (*arr)[rows] = malloc( sizeof *arr * cols ); > > I've never had any issues, but...does this count as undefined behavior? > `sizeof` evaluates the operand when it's a VLA, but what does "evaluate" > mean in this context? Is it trying to dereference the pointer, or is it > simply determining the size of *any* object the pointer may refer to? In this context evaluate means to compute the int expression rows. That computation is needed to determine the size of the array being pointed to. It is no more necessary to dereference the pointer to the array in this context as in the context of the dimension being a constant expression. --- news://freenews.netfront.net/ - complaints: news@netfront.net ---
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-11-19 13:50 -0800 |
| Message-ID | <e4e8b14f-7766-4058-ae64-980ed1591e54@googlegroups.com> |
| In reply to | #76557 |
On Thursday, November 19, 2015 at 3:40:18 PM UTC-6, A. Bolmarcich wrote: > It is no more necessary to dereference the pointer to the array in this > context as in the context of the dimension being a constant expression. Of course there's no reason why a sane compiler *should* evaluate the expression in this case, but N1570 6.5.3.4(2) says, with regard to sizeof: 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 Since the evaluation of the expression in this case would never have any defined side-effects, the as-if rule would allow a compiler to omit such evaluation and any sane compiler would do so. That does not change the fact that nothing would prohibit a compiler from omitting all code which could not execute without code reaching that initialization expression.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-11-19 17:50 -0500 |
| Message-ID | <n2ljik$iqo$1@dont-email.me> |
| In reply to | #76544 |
On 11/19/2015 02:39 PM, John Bode wrote: > I've been using the following idiom a lot to dynamically allocate > 2D arrays: > > T (*arr)[N] = malloc( sizeof *arr * M ); M=>N? > Works great where N is known at compile time. However, I've also been > applying it to VLAs, like so: > > size_t rows; > size_t cols; > ... > T (*arr)[rows] = malloc( sizeof *arr * cols ); > > I've never had any issues, but...does this count as undefined behavior? > `sizeof` evaluates the operand when it's a VLA, but what does "evaluate" > mean in this context? Is it trying to dereference the pointer, or is it > simply determining the size of *any* object the pointer may refer to? The key thing about VLA types is that their sized depends upon the value of one or more expressions, in this case the relevant expression is "rows". The evaluation it's talking about is the evaluation of that expression. Unless the expression has side-effects (for example, rows++), the possibility of it being evaluated is not an issue you need to worry about. -- James Kuyper
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-11-19 15:31 -0800 |
| Message-ID | <8855751e-3de0-471f-98ac-88388962cb02@googlegroups.com> |
| In reply to | #76564 |
On Thursday, November 19, 2015 at 4:50:22 PM UTC-6, James Kuyper wrote: > Unless the expression has side-effects (for example, > rows++), the possibility of it being evaluated is not an issue you need > to worry about. It's not a possibility one would need to worry about when using a sane compiler. Unfortunately, some compiler writers seem to pride themselves in the ability to detect situations where the Standard would impose no requirements, and omit code which would otherwise handle those situations.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-11-20 01:09 +0000 |
| Message-ID | <87k2pdsci3.fsf@bsb.me.uk> |
| In reply to | #76564 |
James Kuyper <jameskuyper@verizon.net> writes: > On 11/19/2015 02:39 PM, John Bode wrote: >> I've been using the following idiom a lot to dynamically allocate >> 2D arrays: >> >> T (*arr)[N] = malloc( sizeof *arr * M ); > > M=>N? > >> Works great where N is known at compile time. However, I've also been >> applying it to VLAs, like so: >> >> size_t rows; >> size_t cols; >> ... >> T (*arr)[rows] = malloc( sizeof *arr * cols ); >> >> I've never had any issues, but...does this count as undefined behavior? >> `sizeof` evaluates the operand when it's a VLA, but what does "evaluate" >> mean in this context? Is it trying to dereference the pointer, or is it >> simply determining the size of *any* object the pointer may refer to? > > The key thing about VLA types is that their sized depends upon the value > of one or more expressions, in this case the relevant expression is > "rows". The evaluation it's talking about is the evaluation of that > expression. I don't see how you can get from the wording in the standard to that conclusion. The wording about sizeof states that "...if the type of the operand is a variable length array type, the operand is evaluated;" Isn't *arr the operand and isn't its type a variable length array type? <snip> -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-11-19 19:10 -0800 |
| Message-ID | <a715332a-b350-4252-9c4a-0301d51e2127@googlegroups.com> |
| In reply to | #76588 |
On Thursday, November 19, 2015 at 7:09:25 PM UTC-6, Ben Bacarisse wrote: > Isn't *arr the operand and isn't its type a variable length array type? In all *defined* cases, a compiler would be required to behave as though it evaluted *arr, but there is no defined case where evaluation of *arr would have any effect [actually, there are no defined cases at all] and thus there is no reason a sane compiler would generate code to evaluate it. On the other hand, a compiler whose goal is to generate the most efficient code that complies with the Standard (as opposed to the most efficient code that meets programmer requirements) might also determine that the Standard does not require anything after the expression to be evaluated either.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-11-20 03:52 -0800 |
| Message-ID | <ln610wevm8.fsf@kst-u.example.com> |
| In reply to | #76564 |
James Kuyper <jameskuyper@verizon.net> writes:
> On 11/19/2015 02:39 PM, John Bode wrote:
>> I've been using the following idiom a lot to dynamically allocate
>> 2D arrays:
>>
>> T (*arr)[N] = malloc( sizeof *arr * M );
>
> M=>N?
>
>> Works great where N is known at compile time. However, I've also been
>> applying it to VLAs, like so:
>>
>> size_t rows;
>> size_t cols;
>> ...
>> T (*arr)[rows] = malloc( sizeof *arr * cols );
>>
>> I've never had any issues, but...does this count as undefined behavior?
>> `sizeof` evaluates the operand when it's a VLA, but what does "evaluate"
>> mean in this context? Is it trying to dereference the pointer, or is it
>> simply determining the size of *any* object the pointer may refer to?
>
> The key thing about VLA types is that their sized depends upon the value
> of one or more expressions, in this case the relevant expression is
> "rows". The evaluation it's talking about is the evaluation of that
> expression. Unless the expression has side-effects (for example,
> rows++), the possibility of it being evaluated is not an issue you need
> to worry about.
No, the expression `rows` is not evaluated.
Consider:
size_t rows = 10;
char vla[rows];
rows = 20;
sizeof vla;
`sizeof vla` is 10, not 20. Evaluating `rows` is not just
unnecessary; it gives the wrong result.
I think the standard is just being sloppy to the point of being
incorrect here. For non-VLA types, `sizeof expr` and `sizeof
(typename)` are evaluated at compile time.
For an expression of a VLA type, `sizeof expr` has to be determined
at run time, but the only thing that actually needs to be evaluated
is the stored value of whatever anonymous object the compiler
uses to remember the size (with perhaps some other computation if,
for example, the stored value is an element count). Neither the
expression that determined the size (whose value may not be the same)
nor the value of the array object (which consists of the values of
its elements) actually needs to be evaluated.
For `sizeof` applied to a parenthesized VLA type, any expressions
that are part of the type name have to be evaluated. For example,
in `sizeof (char[func()])`, the function has to be called and any
side effects must occur; similarly for `sizeof (char[n++])`.
The standard doesn't actually manage to say all this, but I think
that's the only reasonable interpretation of the intent.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-11-20 14:24 +0000 |
| Message-ID | <87mvu8rbor.fsf@bsb.me.uk> |
| In reply to | #76625 |
Keith Thompson <kst-u@mib.org> writes: > James Kuyper <jameskuyper@verizon.net> writes: >> On 11/19/2015 02:39 PM, John Bode wrote: >>> I've been using the following idiom a lot to dynamically allocate >>> 2D arrays: >>> >>> T (*arr)[N] = malloc( sizeof *arr * M ); >> >> M=>N? >> >>> Works great where N is known at compile time. However, I've also been >>> applying it to VLAs, like so: >>> >>> size_t rows; >>> size_t cols; >>> ... >>> T (*arr)[rows] = malloc( sizeof *arr * cols ); >>> >>> I've never had any issues, but...does this count as undefined behavior? >>> `sizeof` evaluates the operand when it's a VLA, but what does "evaluate" >>> mean in this context? Is it trying to dereference the pointer, or is it >>> simply determining the size of *any* object the pointer may refer to? >> >> The key thing about VLA types is that their sized depends upon the value >> of one or more expressions, in this case the relevant expression is >> "rows". The evaluation it's talking about is the evaluation of that >> expression. Unless the expression has side-effects (for example, >> rows++), the possibility of it being evaluated is not an issue you need >> to worry about. > > No, the expression `rows` is not evaluated. > > Consider: > > size_t rows = 10; > char vla[rows]; > rows = 20; > sizeof vla; > > `sizeof vla` is 10, not 20. Evaluating `rows` is not just > unnecessary; it gives the wrong result. > > I think the standard is just being sloppy to the point of being > incorrect here. For non-VLA types, `sizeof expr` and `sizeof > (typename)` are evaluated at compile time. I agree that the wording probably does not say what was intended. Unfortunately it's not really unclear so what should a conforming compiler do? > > For an expression of a VLA type, `sizeof expr` has to be determined > at run time, but the only thing that actually needs to be evaluated > is the stored value of whatever anonymous object the compiler > uses to remember the size (with perhaps some other computation if, > for example, the stored value is an element count). Neither the > expression that determined the size (whose value may not be the same) > nor the value of the array object (which consists of the values of > its elements) actually needs to be evaluated. > > For `sizeof` applied to a parenthesized VLA type, any expressions > that are part of the type name have to be evaluated. For example, > in `sizeof (char[func()])`, the function has to be called and any > side effects must occur; similarly for `sizeof (char[n++])`. But, as I am sure you know, the wording in the standard goes further. If we replace *arr with arr[0] but with the 0 being produced by a function call: sizeof arr[f()] then the wording says that f must be called. gcc obliges but clang does not. (No implementation is required to go any further and actually access the as yet non-existent array, but the standard, as worded, implies that the above, and the original, are undefined.) > The standard doesn't actually manage to say all this, but I think > that's the only reasonable interpretation of the intent. As you say, the intent may well have been to limit evaluation to expressions contained in type names of VLAs, but it certainly doesn't say that, and at least one implementation has taken the literal meaning. Maybe rather than this: "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 was meant was this: "If the operand is a variable length array type name, any expressions in the operand are evaluated; otherwise, the operand is not evaluated and the result is an integer constant." -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-11-20 10:25 -0800 |
| Message-ID | <10aa86e7-9158-4ee3-b096-969fe6aff91b@googlegroups.com> |
| In reply to | #76631 |
On Friday, November 20, 2015 at 8:24:41 AM UTC-6, Ben Bacarisse wrote: > what was meant was this: > > "If the operand is a variable length array type name, any expressions > in the operand are evaluated; otherwise, the operand is not evaluated > and the result is an integer constant." A simpler way to say that would be that any expression within a sizeof expression which would have a *syntactically defined effect* upon the value returned by sizeof must be evaluated whether or not the value yielded by sizeof is used for any purpose. If one were to replace all array lengths in the sizeof expression with identifiers expr1, expr2, etc. syntactic analysis would make it clear which ones were relevant to the overall value of the expression and which ones were not.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-11-20 18:29 -0800 |
| Message-ID | <lnsi40axv9.fsf@kst-u.example.com> |
| In reply to | #76631 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> Keith Thompson <kst-u@mib.org> writes:
>> James Kuyper <jameskuyper@verizon.net> writes:
>>> On 11/19/2015 02:39 PM, John Bode wrote:
>>>> I've been using the following idiom a lot to dynamically allocate
>>>> 2D arrays:
>>>>
>>>> T (*arr)[N] = malloc( sizeof *arr * M );
>>>
>>> M=>N?
>>>
>>>> Works great where N is known at compile time. However, I've also been
>>>> applying it to VLAs, like so:
>>>>
>>>> size_t rows;
>>>> size_t cols;
>>>> ...
>>>> T (*arr)[rows] = malloc( sizeof *arr * cols );
>>>>
>>>> I've never had any issues, but...does this count as undefined behavior?
>>>> `sizeof` evaluates the operand when it's a VLA, but what does "evaluate"
>>>> mean in this context? Is it trying to dereference the pointer, or is it
>>>> simply determining the size of *any* object the pointer may refer to?
>>>
>>> The key thing about VLA types is that their sized depends upon the value
>>> of one or more expressions, in this case the relevant expression is
>>> "rows". The evaluation it's talking about is the evaluation of that
>>> expression. Unless the expression has side-effects (for example,
>>> rows++), the possibility of it being evaluated is not an issue you need
>>> to worry about.
>>
>> No, the expression `rows` is not evaluated.
>>
>> Consider:
>>
>> size_t rows = 10;
>> char vla[rows];
>> rows = 20;
>> sizeof vla;
>>
>> `sizeof vla` is 10, not 20. Evaluating `rows` is not just
>> unnecessary; it gives the wrong result.
>>
>> I think the standard is just being sloppy to the point of being
>> incorrect here. For non-VLA types, `sizeof expr` and `sizeof
>> (typename)` are evaluated at compile time.
>
> I agree that the wording probably does not say what was intended.
> Unfortunately it's not really unclear so what should a conforming
> compiler do?
>>
>> For an expression of a VLA type, `sizeof expr` has to be determined
>> at run time, but the only thing that actually needs to be evaluated
>> is the stored value of whatever anonymous object the compiler
>> uses to remember the size (with perhaps some other computation if,
>> for example, the stored value is an element count). Neither the
>> expression that determined the size (whose value may not be the same)
>> nor the value of the array object (which consists of the values of
>> its elements) actually needs to be evaluated.
>>
>> For `sizeof` applied to a parenthesized VLA type, any expressions
>> that are part of the type name have to be evaluated. For example,
>> in `sizeof (char[func()])`, the function has to be called and any
>> side effects must occur; similarly for `sizeof (char[n++])`.
>
> But, as I am sure you know, the wording in the standard goes further.
> If we replace *arr with arr[0] but with the 0 being produced by a
> function call:
>
> sizeof arr[f()]
>
> then the wording says that f must be called. gcc obliges but clang does
> not. (No implementation is required to go any further and actually
> access the as yet non-existent array, but the standard, as worded,
> implies that the above, and the original, are undefined.)
Interesting point. Here's an example:
#include <stdio.h>
int zero(void) {
puts("zero()");
return 0;
}
int main(void) {
int n = 10;
char vla[n][n];
printf("sizeof vla[zero()] = %zu\n", sizeof vla[zero()]);
}
The output using every version of gcc and clang I've tried is:
zero()
sizeof vla[zero()] = 10
The sizeof computation is correct, but it *could* have been determined
without calling the function. As far as I can tell, the value returned
by the call to zero() can have no effect on the result of the sizeof
computation.
>> The standard doesn't actually manage to say all this, but I think
>> that's the only reasonable interpretation of the intent.
>
> As you say, the intent may well have been to limit evaluation to
> expressions contained in type names of VLAs, but it certainly doesn't
> say that, and at least one implementation has taken the literal meaning.
>
> Maybe rather than this:
>
> "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 was meant was this:
>
> "If the operand is a variable length array type name, any expressions
> in the operand are evaluated; otherwise, the operand is not evaluated
> and the result is an integer constant."
The result of `sizeof vla_object` is not an integer constant. (Aside:
"integer constant" is a poor choice of words, since that phrase has a
different meaning.)
The type of the operand to sizeof is known at compile time, and
I believe that the size of that type can always be determined
without evaluating anything other than the values of anonymous
compiler-generated objects (or whatever mechanism the implementation
uses to remember the size of a VLA type).
I suggest something like:
If the operand is a parenthesized variable length array type name,
any expressions in the operand are evaluated. Otherwise, the
operand is not evaluated. The result is constant unless the
type of the operand is a variable length array type.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2015-11-21 16:35 +1300 |
| Message-ID | <dba734FjpqnU6@mid.individual.net> |
| In reply to | #76708 |
Keith Thompson wrote:
> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>>
>> But, as I am sure you know, the wording in the standard goes further.
>> If we replace *arr with arr[0] but with the 0 being produced by a
>> function call:
>>
>> sizeof arr[f()]
>>
>> then the wording says that f must be called. gcc obliges but clang does
>> not. (No implementation is required to go any further and actually
>> access the as yet non-existent array, but the standard, as worded,
>> implies that the above, and the original, are undefined.)
>
> Interesting point. Here's an example:
>
> #include <stdio.h>
>
> int zero(void) {
> puts("zero()");
> return 0;
> }
>
> int main(void) {
> int n = 10;
> char vla[n][n];
> printf("sizeof vla[zero()] = %zu\n", sizeof vla[zero()]);
> }
>
> The output using every version of gcc and clang I've tried is:
>
> zero()
> sizeof vla[zero()] = 10
>
> The sizeof computation is correct, but it *could* have been determined
> without calling the function. As far as I can tell, the value returned
> by the call to zero() can have no effect on the result of the sizeof
> computation.
Is this a case of the observer effect?
I tired you code with Sun c99 and the whether the puts() line was there
or not, the immediate value 10 was pushed.
--
Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-11-20 20:24 -0800 |
| Message-ID | <lnd1v49dz5.fsf@kst-u.example.com> |
| In reply to | #76715 |
Ian Collins <ian-news@hotmail.com> writes:
> Keith Thompson wrote:
[...]
>> Interesting point. Here's an example:
>>
>> #include <stdio.h>
>>
>> int zero(void) {
>> puts("zero()");
>> return 0;
>> }
>>
>> int main(void) {
>> int n = 10;
>> char vla[n][n];
>> printf("sizeof vla[zero()] = %zu\n", sizeof vla[zero()]);
>> }
>>
>> The output using every version of gcc and clang I've tried is:
>>
>> zero()
>> sizeof vla[zero()] = 10
>>
>> The sizeof computation is correct, but it *could* have been determined
>> without calling the function. As far as I can tell, the value returned
>> by the call to zero() can have no effect on the result of the sizeof
>> computation.
>
> Is this a case of the observer effect?
>
> I tired you code with Sun c99 and the whether the puts() line was there
> or not, the immediate value 10 was pushed.
I'm not sure what you mean by "pushed". Are you looking at the
generated code?
I tried the example with a rather old Sun C compiler. The output was:
sizeof vla[zero()] = 10
(Which IMHO *should* be correct, but the call to zero() generated by gcc
and clang follows what the standard says.)
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2015-11-21 17:38 +1300 |
| Message-ID | <dbaappFjpqnU7@mid.individual.net> |
| In reply to | #76720 |
Keith Thompson wrote:
> Ian Collins <ian-news@hotmail.com> writes:
>> Keith Thompson wrote:
> [...]
>>> Interesting point. Here's an example:
>>>
>>> #include <stdio.h>
>>>
>>> int zero(void) {
>>> puts("zero()");
>>> return 0;
>>> }
>>>
>>> int main(void) {
>>> int n = 10;
>>> char vla[n][n];
>>> printf("sizeof vla[zero()] = %zu\n", sizeof vla[zero()]);
>>> }
>>>
>>> The output using every version of gcc and clang I've tried is:
>>>
>>> zero()
>>> sizeof vla[zero()] = 10
>>>
>>> The sizeof computation is correct, but it *could* have been determined
>>> without calling the function. As far as I can tell, the value returned
>>> by the call to zero() can have no effect on the result of the sizeof
>>> computation.
>>
>> Is this a case of the observer effect?
>>
>> I tired you code with Sun c99 and the whether the puts() line was there
>> or not, the immediate value 10 was pushed.
>
> I'm not sure what you mean by "pushed". Are you looking at the
> generated code?
Yes.
> I tried the example with a rather old Sun C compiler. The output was:
>
> sizeof vla[zero()] = 10
>
> (Which IMHO *should* be correct, but the call to zero() generated by gcc
> and clang follows what the standard says.)
If wee look at the gcc output (with -01), with puts():
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
call zero
subl $8, %esp
pushl $10
pushl $.LC1
call printf
addl $16, %esp
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret
Without:
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $12, %esp
pushl $10
pushl $.LC0
call printf
addl $16, %esp
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret
So without puts(), zero() isn't called. Even with it, the return value
isn't used.
--
Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-11-20 21:08 -0800 |
| Message-ID | <lnoaeo7xe1.fsf@kst-u.example.com> |
| In reply to | #76721 |
Ian Collins <ian-news@hotmail.com> writes:
> Keith Thompson wrote:
>> Ian Collins <ian-news@hotmail.com> writes:
>>> Keith Thompson wrote:
>> [...]
>>>> Interesting point. Here's an example:
>>>>
>>>> #include <stdio.h>
>>>>
>>>> int zero(void) {
>>>> puts("zero()");
>>>> return 0;
>>>> }
>>>>
>>>> int main(void) {
>>>> int n = 10;
>>>> char vla[n][n];
>>>> printf("sizeof vla[zero()] = %zu\n", sizeof vla[zero()]);
>>>> }
>>>>
>>>> The output using every version of gcc and clang I've tried is:
>>>>
>>>> zero()
>>>> sizeof vla[zero()] = 10
>>>>
>>>> The sizeof computation is correct, but it *could* have been determined
>>>> without calling the function. As far as I can tell, the value returned
>>>> by the call to zero() can have no effect on the result of the sizeof
>>>> computation.
>>>
>>> Is this a case of the observer effect?
>>>
>>> I tired you code with Sun c99 and the whether the puts() line was there
>>> or not, the immediate value 10 was pushed.
>>
>> I'm not sure what you mean by "pushed". Are you looking at the
>> generated code?
>
> Yes.
>
>> I tried the example with a rather old Sun C compiler. The output was:
>>
>> sizeof vla[zero()] = 10
>>
>> (Which IMHO *should* be correct, but the call to zero() generated by gcc
>> and clang follows what the standard says.)
>
> If wee look at the gcc output (with -01), with puts():
>
> main:
[snip]
> call zero
[snip]
>
> Without:
>
> main:
> leal 4(%esp), %ecx
> andl $-16, %esp
> pushl -4(%ecx)
> pushl %ebp
> movl %esp, %ebp
> pushl %ecx
> subl $12, %esp
> pushl $10
> pushl $.LC0
> call printf
> addl $16, %esp
> movl -4(%ebp), %ecx
> leave
> leal -4(%ecx), %esp
> ret
>
> So without puts(), zero() isn't called. Even with it, the return value
> isn't used.
Without puts(), the call to zero() is simply being implicitly inlined.
Logically, it's still being called; the call is just optimized to a
constant value of 0. The same thing happens for a call that's not part
of the operand of sizeof.
The side effect of the puts() call is needed to demonstrate that the
operand of sizeof is or is not being evaluated.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-11-21 10:46 +0000 |
| Message-ID | <871tbjpr4m.fsf@bsb.me.uk> |
| In reply to | #76708 |
Keith Thompson <kst-u@mib.org> writes: > Ben Bacarisse <ben.usenet@bsb.me.uk> writes: <snip> >> If we replace *arr with arr[0] but with the 0 being produced by a >> function call: >> >> sizeof arr[f()] >> >> then the wording says that f must be called. gcc obliges but clang does >> not. <snip example> > The output using every version of gcc and clang I've tried is: > > zero() > sizeof vla[zero()] = 10 And I've just tried to see how I determined that clang did not evaluate the argument to sizeof and I could not. I don't know why I thought it didn't but I agree that gcc clang to the same with your example (and now, it seems, with mine!). <snip> >> As you say, the intent may well have been to limit evaluation to >> expressions contained in type names of VLAs, but it certainly doesn't >> say that, and at least one implementation has taken the literal meaning. >> >> Maybe rather than this: >> >> "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 was meant was this: >> >> "If the operand is a variable length array type name, any expressions >> in the operand are evaluated; otherwise, the operand is not evaluated >> and the result is an integer constant." > > The result of `sizeof vla_object` is not an integer constant. (Aside: > "integer constant" is a poor choice of words, since that phrase has a > different meaning.) Agreed. > The type of the operand to sizeof is known at compile time, and > I believe that the size of that type can always be determined > without evaluating anything other than the values of anonymous > compiler-generated objects (or whatever mechanism the implementation > uses to remember the size of a VLA type). > > I suggest something like: > > If the operand is a parenthesized variable length array type name, > any expressions in the operand are evaluated. Otherwise, the > operand is not evaluated. The result is constant unless the > type of the operand is a variable length array type. I find the idea that the result of an expression might be anything but constant rather odd. Would "The result is *a* constant" be better? But then does the last sentence add anything very useful? I'd be inclined to omit it. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-11-21 03:26 -0800 |
| Message-ID | <lnbnan8uf7.fsf@kst-u.example.com> |
| In reply to | #76746 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> Keith Thompson <kst-u@mib.org> writes:
[...]
>> I suggest something like:
>>
>> If the operand is a parenthesized variable length array type name,
>> any expressions in the operand are evaluated. Otherwise, the
>> operand is not evaluated. The result is constant unless the
>> type of the operand is a variable length array type.
>
> I find the idea that the result of an expression might be anything but
> constant rather odd. Would "The result is *a* constant" be better? But
> then does the last sentence add anything very useful? I'd be inclined
> to omit it.
Are you thinking that "constant" means "read-only"? That's "const",
which is not at all the same thing as "constant".
The word "constant" means, basically, "evaluated at compile time".
Specifically a constant expression is one that can be evaluated at
compile time; the full definition is in N1570 6.6.
1+1 is a constant expression; n+1 is not (unless n is an enumeration
constant).
*A* constant is a lexical element, such as 42, 1.5, or '?'.
`sizeof expression` and `sizeof ( type-name )` are both unary
expressions. A better formulation, I think, is:
If the operand is a parenthesized variable length array type name,
any expressions in the operand are evaluated. Otherwise, the
operand is not evaluated. The unary expression is an integer
constant expression unless the type of the operand is a variable
length array type.
This covers all 4 cases:
1. sizeof vla_expr
Not a constant expression, but the operand is not evaluated.
This differs from what the standard currently says.
2. sizeof ( vla_type )
Not a constant expression. Any expressions that are part of the type
name are evaluated
3. sizeof non_vla_expr
This is a constant expression. The operand is not evaluated.
4. sizeof ( non_vla_type )
This is a constant expression. Any expressions that are part of the
type name are evaluated -- but since they can only be constant
expressions, there are no side effects. (Consider `sizeof ( int[10] )`;
10 is evaluated at compile time.)
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-11-21 12:46 +0000 |
| Message-ID | <87k2pbo6z6.fsf@bsb.me.uk> |
| In reply to | #76753 |
Keith Thompson <kst-u@mib.org> writes: > Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >> Keith Thompson <kst-u@mib.org> writes: > [...] >>> I suggest something like: >>> >>> If the operand is a parenthesized variable length array type name, >>> any expressions in the operand are evaluated. Otherwise, the >>> operand is not evaluated. The result is constant unless the >>> type of the operand is a variable length array type. >> >> I find the idea that the result of an expression might be anything but >> constant rather odd. Would "The result is *a* constant" be better? But >> then does the last sentence add anything very useful? I'd be inclined >> to omit it. > > Are you thinking that "constant" means "read-only"? That's "const", > which is not at all the same thing as "constant". > > The word "constant" means, basically, "evaluated at compile time". > Specifically a constant expression is one that can be evaluated at > compile time; the full definition is in N1570 6.6. No, I'm thinking of the word used in the normal sense. The result of f()+1 is, to my mind, constant. It is not const and it's not a constant expression, but all three are different things. 6.6 defines constant expressions, so that phrase would be better if that is what you intended. <snip> > ... A better formulation, I think, is: > > If the operand is a parenthesized variable length array type name, > any expressions in the operand are evaluated. Otherwise, the > operand is not evaluated. The unary expression is an integer > constant expression unless the type of the operand is a variable > length array type. Ah, yes, that's better in my opinion too. <snip detail> -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-11-21 14:01 +0000 |
| Message-ID | <87egfjo3i9.fsf@bsb.me.uk> |
| In reply to | #76760 |
ram@zedat.fu-berlin.de (Stefan Ram) writes: > Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >>No, I'm thinking of the word used in the normal sense. The result of >>f()+1 is, to my mind, constant. > > I can't see the reason for this use of »constant«. Neither can I. That's why I thought it a slightly odd phrase. A value is, almost by definition, constant. <snip> -- Ben.
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.c
csiph-web