sizeof operator in C

D

deepak

Hi,

Why an increment like sizeof(i++) is not incrementing value of i?

Thanks,
Deepak
 
N

Nick Keighley

Why an increment like sizeof(i++) is not incrementing value of i?

sizeof isn't a function but a compile time operator. The compiler
doesn't need the value of i but only its type. It evaluates this at
compile
time and just stuffs a constant it.

j = sizeof(i++) + j;

just gets replaced with
j = 4 + j;

(assuming an int is 4 bytes)
 
L

Loïc Domaigné

Hello,
Why an increment like sizeof(i++) is not incrementing value of i?

Accordingly to ANSI C, the sizeof operand may be a rvalue, but the
expression is not evaluated. The compiler only looks at the resulting
type to determine the size of the object required to hold "i++".

HTH,
Loïc
 
J

James Kuyper

deepak said:
Hi,

Why an increment like sizeof(i++) is not incrementing value of i?

At one level, the answer is that the standard specifies that it should
not be incremented:

"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
a integer constant." (6.5.3.4p1) Note that the exception for VLAs is new
in C99; in C90 the operand is never evaluated.

If you're asking why the standard says this, the reason is that the
intended use for sizeof was one for which it would, more often than not,
be inconvenient for it to evaluate the expression. All that sizeof needs
to know is the type of the expression that it operates on. Except when
the argument is a VLA (which is why VLAs are an exception), that size
can be determined at compile time and used wherever an integer constant
expression might be used.
 
P

peacepanda3

Also, consider that evaluating the expression could result in UB:

     static int *pt = NULL;
     ...
     pt = realloc(pt,newsize*sizeof(*pt));

I have seen a lot of posts that constantly use UB but couldnt exactly
figure out what does it stand for can you please tell me what does it
mean.
 
B

Beej Jorgensen

pete said:
VLA's are a needless complication of the language.

I swear this one should go in the FAQ! :)

Rationale 6.7.5.2p20:
# C99 adds a new array type called a variable length array type. The
# inability to declare arrays whose size is known only at execution time
# was often cited as a primary deterrent to using C as a numerical
# computing language. Adoption of some standard notion of execution time
# arrays was considered crucial for C's acceptance in the numerical
# computing world.

http://www.ddj.com/cpp/184401444 VLAs Part 1
http://www.ddj.com/cpp/184401468 VLAs Part 2
http://www.ddj.com/cpp/184401476 VLAs Part 3
http://www.ddj.com/cpp/184401497 VLAs Part 4

For better or worse, there it is.

-Beej
 
J

James Kuyper

pete said:
VLA's are a needless complication of the language.

++ is also a needless complication. It's a useful one, however. I've not
had a chance to make serious use of C99, but I know of some code I'd
like to re-write to take advantage of VLAs.

It uses multi-dimensional arrays two or more of whose dimensions are not
known until run-time. The current version wastes a lot of space
declaring arrays of the maximum possible size in each dimension, and
needs to repackage the arrays into a buffer for certain third-party
library functions that expect consecutive rows of the array to be
adjacent with no unused gaps. It should be a lot simpler and use a lot
less space with VLAs.

I know very well how to emulate a multi-dimensional array of variable
dimensions using a one-dimensional array, and this code uses that
technique, too. Removing the code that performs that emulation is part
of the simplification I'm looking forward to.
 
G

Guest

| If you're asking why the standard says this, the reason is that the
| intended use for sizeof was one for which it would, more often than not,
| be inconvenient for it to evaluate the expression. All that sizeof needs
| to know is the type of the expression that it operates on. Except when
| the argument is a VLA (which is why VLAs are an exception), that size
| can be determined at compile time and used wherever an integer constant
| expression might be used.

It should only need to evaluate the expression that determines the VLA size.
If the expression given to sizeof is more complex and the VLA and its size
is just a part, does the whole thing get evaluated? If the expression has
side effects like an increment, and the same VLA is used many times, does
this always increment each time? IWSTM that once the size is determined for
a VLA, such as entry to a function or block, then all references to the VLA
size should just extract that predetermined value.
 
K

Keith Thompson

On Tue, 04 Aug 2009 13:39:45 GMT James Kuyper
| If you're asking why the standard says this, the reason is that the
| intended use for sizeof was one for which it would, more often than not,
| be inconvenient for it to evaluate the expression. All that sizeof needs
| to know is the type of the expression that it operates on. Except when
| the argument is a VLA (which is why VLAs are an exception), that size
| can be determined at compile time and used wherever an integer constant
| expression might be used.

It should only need to evaluate the expression that determines the VLA size.
If the expression given to sizeof is more complex and the VLA and its size
is just a part, does the whole thing get evaluated? If the expression has
side effects like an increment, and the same VLA is used many times, does
this always increment each time? IWSTM that once the size is determined for
a VLA, such as entry to a function or block, then all references to the VLA
size should just extract that predetermined value.

sizeof applied to a VLA doesn't reevaluate the expression that
determined the size of the VLA, because the result of the expression
can change but the size of the VLA is fixed once it's created:

{
int n = 10;
char vla[n];
n = 20;
printf("n = %d, sizeof vla = %zu\n", n, sizeof vla);
/* prints "n = 10, sizeof vla = 20 */
}

In this particular case, the expression "sizeof vla" *could* be
optimized to a constant 10, but in the general case there has to be
some run-time evaluation.

C99 6.5.3.4p2 says:

If the type of the operand is a variable length array type, the
operand is evaluated; otherwise, the operand is not evaluated and
the result is an integer constant.

IMHO this wording could use some improvement. If the operand
is a VLA object, then it doesn't need to evaluate the object,
and in some cases it shouldn't. For example, if you have a VLA
of volatile elements, sizeof doesn't need to, and shouldn't,
trigger whatever side effects might be caused by evaluating them.
And if the operand is a parenthesized VLA type, such as ``sizeof
(char[n])'', it needs to evaluate whatever expressions are included
in the type name; I suppose that's sufficiently obvious from "the
operand is evaluated", but a bit more clarity would be good.

Note that this applies only when the operand's type is a VLA type.
You asked about cases where "the expression given to sizeof is more
complex and the VLA and its size is just a part". I can't think
of any examples of that; can you?
 
J

James Kuyper

| If you're asking why the standard says this, the reason is that the
| intended use for sizeof was one for which it would, more often than not,
| be inconvenient for it to evaluate the expression. All that sizeof needs
| to know is the type of the expression that it operates on. Except when
| the argument is a VLA (which is why VLAs are an exception), that size
| can be determined at compile time and used wherever an integer constant
| expression might be used.

It should only need to evaluate the expression that determines the VLA size.
If the expression given to sizeof is more complex and the VLA and its size
is just a part, does the whole thing get evaluated? If the expression has
side effects like an increment, and the same VLA is used many times, does
this always increment each time? IWSTM that once the size is determined for
a VLA, such as entry to a function or block, then all references to the VLA
size should just extract that predetermined value.

I understand your point, but the committee decided to ignore all of
those complicated issues in favor of keeping the rule simple: "If the
type of the operand is a variable length array type, the operand is
evaluated;" (6.5.3.4p2). No partial evaluation, no one-time only
evaluation. The whole operand is evaluated, every time that such a
sizeof expression needs to be evaluated.
 
K

Kaz Kylheku

| If you're asking why the standard says this, the reason is that the
| intended use for sizeof was one for which it would, more often than not,
| be inconvenient for it to evaluate the expression. All that sizeof needs
| to know is the type of the expression that it operates on. Except when
| the argument is a VLA (which is why VLAs are an exception), that size
| can be determined at compile time and used wherever an integer constant
| expression might be used.

It should only need to evaluate the expression that determines the VLA size.
If the expression given to sizeof is more complex and the VLA and its size
is just a part, does the whole thing get evaluated?

If the expression given to sizeof is complex, and contains some kind of
reference to a VLA, then the argument of this sizeof is not a VLA expression.

Thus the rule does not apply; the expression is not evaluated.

Thus ``sizeof vla + 0'' is still a constant expression, in which the primary
expression ``vla'' is not evaluated.

Perhaps a better example is ``sizeof sizeof vla'' where the vla is not
evaluated, because the sizeof vla itself is not evaluated, being a non-VLA
argument of the sizeof. It's a constant expression equivalent to
sizeof (size_t).
If the expression has
side effects like an increment, and the same VLA is used many times, does
this always increment each time? IWSTM that once the size is determined for
a VLA, such as entry to a function or block, then all references to the VLA
size should just extract that predetermined value.

If you have any local variable that is assigned once and never modified, then
all accesses to that variable can just be replaced by a cached value.
This kind of optimization is allowed because accesses to an object that is not
volatile-qualified aren't a side effect.

However, those accesses are understood to evaluate the abstract object.
 

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

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,218
Latest member
JolieDenha

Latest Threads

Top