Redundant statement in the Standard?

M

Martin Wells

Someone posted the following excerpt recently in relation to the
sizeof operator:

6.5.3.4p2: "... 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."

The first thing that occured to me was that nothing happens when you
evaluate a VLA. I mean what's the following supposed to do?

{
int arr[some_runtime_figure];

arr;
}

So then I tried to think what *other* expressions could be a VLA. My
first thought was a function, but the following won't compile for me
with a C99 compiler, it says C99 doesn't allow to return an array from
a function:

int Func(void)[5]
{
int arr[5] = {0};

return arr;
}

int main(void)
{
sizeof(Func());
}

Then I used even more of my brain and realised that I hard-coded 5
into the function signature so I wouldn't be able to return a VLA
anyway.

So I'm left wondering, what kind of expression is a VLA, but which
also DOES SOMETHING? What was the purpose of adding that little
paragraph to the Standard?

Would it not have been simpler to leave us with the universal "sizeof
doesn't evaluate its operand"?

Martin
 
R

Richard Bos

Martin Wells said:
Someone posted the following excerpt recently in relation to the
sizeof operator:

6.5.3.4p2: "... 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."

The first thing that occured to me was that nothing happens when you
evaluate a VLA.

Consider an expression whose type is a VLA, but whose evaluation
involves side effects. For example, given

size_t n=some_expression();
char arr[14][n]
size_t i=0;

the operation

sizeof (arr[i++])

would return the size of the VLA (which should be n), _and_ increment i.
This is unfortunate, because had the declaration of n been

#define n 93

the very same code would have returned the size of the _non_-VLA (to
wit, 93), and _not_ incremented i.

The moral? Never include side-effects in the operands to sizeof, so that
surprise is minimised.

Richard
 
C

Charlie Gordon

Richard Bos said:
Martin Wells said:
Someone posted the following excerpt recently in relation to the
sizeof operator:

6.5.3.4p2: "... 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."

The first thing that occured to me was that nothing happens when you
evaluate a VLA.

Consider an expression whose type is a VLA, but whose evaluation
involves side effects. For example, given

size_t n=some_expression();
char arr[14][n]
size_t i=0;

the operation

sizeof (arr[i++])

would return the size of the VLA (which should be n), _and_ increment i.
This is unfortunate, because had the declaration of n been

#define n 93

the very same code would have returned the size of the _non_-VLA (to
wit, 93), and _not_ incremented i.

The moral? Never include side-effects in the operands to sizeof, so that
surprise is minimised.

Actually the moral should be that the Standard has a defect.
Evaluating the argument in not needed to determine the size of the VLA
object, so why should it be mandated ?

Conversely, if the argument is a VLA-type, some form of evaluation would be
necessary, but we would have to define the meaning of "evaluating a
VLA-type."

An example of this is:

int function();

sizeof(char[function()]);

But then it wouldn't be much of a problem is such an expression was left as
invoking undefined behaviour.
 
M

Michal Nazarewicz

Consider an expression whose type is a VLA, but whose evaluation
involves side effects. For example, given

size_t n=some_expression();
char arr[14][n]
size_t i=0;

the operation

sizeof (arr[i++])

would return the size of the VLA (which should be n), _and_ increment i.

No, I don't think that's the case. arr[i++] is not a VLA -- it's
a character hence sizeof would return 1 and there will be no side
effects.

I suppose that valid example is "sizeof(char[n])" where n is not
a constant.
 
R

Richard Bos

Michal Nazarewicz said:
Consider an expression whose type is a VLA, but whose evaluation
involves side effects. For example, given

size_t n=some_expression();
char arr[14][n]
size_t i=0;

the operation

sizeof (arr[i++])

would return the size of the VLA (which should be n), _and_ increment i.

No, I don't think that's the case. arr[i++] is not a VLA -- it's
a character hence sizeof would return 1 and there will be no side
effects.

Read again. arr is an array of VLAs, so arr[i++] is the i'th VLA.
arr[i++][4] would be a char.
I suppose that valid example is "sizeof(char[n])" where n is not
a constant.

That, too, if n has side effects.

Richard
 
M

Michal Nazarewicz

Consider an expression whose type is a VLA, but whose evaluation
involves side effects. For example, given

size_t n=some_expression();
char arr[14][n]
size_t i=0;

the operation

sizeof (arr[i++])

would return the size of the VLA (which should be n), _and_ increment i.
Michal Nazarewicz said:
No, I don't think that's the case. arr[i++] is not a VLA -- it's
a character hence sizeof would return 1 and there will be no side
effects.

Read again. arr is an array of VLAs, so arr[i++] is the i'th VLA.
arr[i++][4] would be a char.

Oh... sorry. You're right. :)
 
C

CBFalconer

Richard said:
.... snip ...
No, I don't think that's the case. arr[i++] is not a VLA -- it's
a character hence sizeof would return 1 and there will be no side
effects.

Read again. arr is an array of VLAs, so arr[i++] is the i'th VLA.
arr[i++][4] would be a char.

You can't have an array of arrays. You can have an array of
pointers to an array.
 
R

Richard Tobin

CBFalconer said:
You can't have an array of arrays. You can have an array of
pointers to an array.

int x[3][5];

declares an array of arrays. You can even have an array of VLAs,
though they must all be the same size.

-- Richard
 
K

Keith Thompson

CBFalconer said:
Richard said:
No, I don't think that's the case. arr[i++] is not a VLA -- it's
a character hence sizeof would return 1 and there will be no side
effects.

Read again. arr is an array of VLAs, so arr[i++] is the i'th VLA.
arr[i++][4] would be a char.

You can't have an array of arrays.

Incorrect, you most certainly can.
You can have an array of
pointers to an array.

Correct (but a pointer to an array is rarely as useful as a pointer to
the first member of an array).
 
R

Richard Bos

CBFalconer said:
Richard said:
Read again. arr is an array of VLAs, so arr[i++] is the i'th VLA.
arr[i++][4] would be a char.

You can't have an array of arrays. You can have an array of
pointers to an array.

From 6.5.2.1:

# 4 EXAMPLE Consider the array object defined by the declaration
# int x[3][5];
# Here x is a 3 ×5 array of ints; more precisely, x is an array of
# three element objects, each of which is an array of five ints.

'tis only a sample, i'faith, but a convincing one at that, marry.

Richard
 
A

Army1987

You can't have an array of arrays. You can have an array of
pointers to an array.

#include <stdio.h>
int main(void)
{
char a[20][20];
char ((*b[20])[20];
printf("%lu %lu\n", (unsigned long)sizeof a,
(unsigned long)sizeof b);
return 0;
}
 
C

CBFalconer

Keith said:
CBFalconer said:
Richard said:
No, I don't think that's the case. arr[i++] is not a VLA -- it's
a character hence sizeof would return 1 and there will be no side
effects.

Read again. arr is an array of VLAs, so arr[i++] is the i'th VLA.
arr[i++][4] would be a char.

You can't have an array of arrays.

Incorrect, you most certainly can.

The original was dealing with an array of VLAs. I omitted the VLA
word in my comment.
 
R

Richard

CBFalconer said:
Richard said:
... snip ...
No, I don't think that's the case. arr[i++] is not a VLA -- it's
a character hence sizeof would return 1 and there will be no side
effects.

Read again. arr is an array of VLAs, so arr[i++] is the i'th VLA.
arr[i++][4] would be a char.

You can't have an array of arrays. You can have an array of
pointers to an array.

What total and utter nonsense. Another example of the c.l.c word games
at their very worst.

int multi[ROWS][COLS];
 
?

=?iso-2022-kr?q?Harald_van_D=0E=29=26=0Fk?=

CBFalconer said:
You can't have an array of arrays. You can have an array of pointers
to an array.

What total and utter nonsense. Another example of the c.l.c word games
at their very worst.

int multi[ROWS][COLS];

It doesn't work as a word game. What you declared is an array of arrays.
multi[0], in most contexts, will be converted to a pointer, but that
doesn't mean it is one. The original claim is simply wrong.
 
K

Keith Thompson

CBFalconer said:
Keith said:
CBFalconer said:
Richard Bos wrote:
... snip ...

No, I don't think that's the case. arr[i++] is not a VLA -- it's
a character hence sizeof would return 1 and there will be no side
effects.

Read again. arr is an array of VLAs, so arr[i++] is the i'th VLA.
arr[i++][4] would be a char.

You can't have an array of arrays.

Incorrect, you most certainly can.

The original was dealing with an array of VLAs. I omitted the VLA
word in my comment.

I think you're still mistaken. As far as I can tell, VLAs of VLAs are
permitted.

The following program:

#include <stdio.h>
int main(void)
{
int n = 10;
char arr[n][n];
printf("sizeof arr[0] = %d\n", (int)sizeof arr[0]);
printf("sizeof arr = %d\n", (int)sizeof arr);
return 0;
}

is accepted without complaint by gcc, icc, and Sun's C compiler under
Solaris 10, and produces the output:

sizeof arr[0] = 10
sizeof arr = 100

(which doesn't actually prove anything), and I don't see any such
restriction in C99 6.7.5.2 (which doesn't really prove anything
either; I might have missed something).

It was also accepted without complaint by Comeau's test drive page,
<http://www.comeaucomputing.com/pcgi-bin/compiler.html>, in strict C99
mode (though that page doesn't give you output).

Can you quote any wording from the standard that forbids VLAs of VLAs?
 
C

CBFalconer

Keith said:
I think you're still mistaken. As far as I can tell, VLAs of VLAs
are permitted.

I differ. Arrays need to be composed of equal sized objects.
VLAs, by nature, are variable sized objects. You could have an
array of pointers to VLAs, though.
 
C

Chris Torek

(They are, necessarily so.)

I differ. Arrays need to be composed of equal sized objects.
VLAs, by nature, are variable sized objects.

This is the tricky part: while VLAs are "variable length arrays",
each *instance* of any given VLA is fixed-size.

VLAs of VLAs are necessary because one of the goals, perhaps even
the primary goal, of VLAs in the first place was to allow C
programmers to write Fortran-like functions with Fortran-like
convenience, e.g.:

/* perform some operation on a matrix of "double" */
void mat_operate(size_t m, size_t n, double mat[m][n]) {
size_t i, j;

for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
... operate on mat[j] ...
}

When mat_operate() is called, m and n are variable, but while
mat_operate() operates, m and n remain fixed. The size of the
matrix "mat" is also fixed.

(This remains true even if m and/or n are modified inside mat_operate().
The size is, in effect, "captured" at the point the VLA is created.)

The key sentences in my draft read:

The size of each instance of a variable length array type
does not change during its lifetime.

and (in part):

... the size of the variable length array type does not change
if the value of n is subsequently changed.
You could have an array of pointers to VLAs, though.

You can indeed have this, as well. You can also have a VLA of
pointers to VLAs, and so on.

The compile-time compatibility rules for pointers to VLAs are
quite relaxed, with the effect at runtime being undefined if the
sizes of the variably-modified types do not match:

void f(size_t n, double square_mat[n][n]) {
double (*p)[rand()]; /* bad idea, for illustration only */

p = square_mat; /* not a compile-time error */
...
}

The effect is undefined unless n happens to be equal to the
value rand() returns. In practice, in a real C compiler, if
rand() returns a number that does not match n, p[0][j] "works
right" but p[j] misbehaves: If we were to capture the
number that came out of the rand() call, e.g., via:

size_t x;
double (*p)[x = rand()];

instead, then p[j] is roughly equivalent to mat[0][i * x + j]
as long as no subscript checking occurs. (Of course, because of
the undefined behavior, the compiler can make various assumptions
and optimize this particular weirdness into *other* weirdness.
For instance, it might make the assumption that x must necessarily
equal n, hence remove x from the runtime image and use the saved
n -- so that p[j] accesses mat[j] after all!)
 
K

Keith Thompson

CBFalconer said:
I differ. Arrays need to be composed of equal sized objects.
VLAs, by nature, are variable sized objects. You could have an
array of pointers to VLAs, though.

You snipped the part where I asked you to provide a citation from the
standard to support your claim. You also snipped the example
demonstrating a VLA of VLAs.

The size of a VLA is fixed at runtime when it's created, and all the
elements of an array of VLAs must have the same size.

If you have a specific reason to think this isn't allowed, I'd love to
hear it (and somebody should submit bug reports against the four
different compilers that didn't complain about VLAs of VLAs).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top