Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #76544 > unrolled thread

sizeof on an uninitialized pointer to a VLA

Started byJohn Bode <jfbode1029@gmail.com>
First post2015-11-19 11:39 -0800
Last post2015-11-21 12:09 -0800
Articles 20 on this page of 22 — 7 participants

Back to article view | Back to comp.lang.c


Contents

  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 →


#76544 — sizeof on an uninitialized pointer to a VLA

FromJohn Bode <jfbode1029@gmail.com>
Date2015-11-19 11:39 -0800
Subjectsizeof 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]


#76549

Fromsupercat@casperkitty.com
Date2015-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]


#76557

From"A. Bolmarcich" <aggedor@earl-grey.cloud9.net>
Date2015-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]


#76558

Fromsupercat@casperkitty.com
Date2015-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]


#76564

FromJames Kuyper <jameskuyper@verizon.net>
Date2015-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]


#76572

Fromsupercat@casperkitty.com
Date2015-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]


#76588

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-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]


#76597

Fromsupercat@casperkitty.com
Date2015-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]


#76625

FromKeith Thompson <kst-u@mib.org>
Date2015-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]


#76631

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-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]


#76658

Fromsupercat@casperkitty.com
Date2015-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]


#76708

FromKeith Thompson <kst-u@mib.org>
Date2015-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]


#76715

FromIan Collins <ian-news@hotmail.com>
Date2015-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]


#76720

FromKeith Thompson <kst-u@mib.org>
Date2015-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]


#76721

FromIan Collins <ian-news@hotmail.com>
Date2015-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]


#76728

FromKeith Thompson <kst-u@mib.org>
Date2015-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]


#76746

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-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]


#76753

FromKeith Thompson <kst-u@mib.org>
Date2015-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]


#76760

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-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]


#76768

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-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