Sizeof query

B

Ben Bacarisse

pete said:
Ben said:
James Kuyper wrote:

Dik T. Winter wrote:

In <[email protected]>, Kenneth
Brody wrote:
...
int main(void)
{
char new = 'z';

printf("%c %ld %c\n",new,(long)sizeof(new++),new);

return(0);
}
...
I don't see any implementation-defined behavior. Did I miss
something in my > desire to become evil?

Isn't sizeof(int) implementation defined?

"The expression ++E is equivalent to (E+=1)." (6.5.3.1p2)

Sorry - wrong operator, wrong citation - I'm not doing well this
morning. Correction:

You're apparently assuming that integer promotions must be applied to
new++. However, as footnote 48 says, "48) The integer promotions are
applied only: as part of the usual arithmetic conversions, to certain
argument expressions, to the operands of the unary +, -, and ~
operators, and to both operands of the shift operators, as specified
by their respective subclauses." Footnotes are not normative, but
footnote 48 correctly summarizes the fact, that you can verify by
reading the normative text, that those are the only locations where
the integer promotions apply. The postfix ++ operator is not one of
those locations.


I disagree. Specifically, I disagree that conversions are excluded
from the ++ operator. Not that it matters in this case, since there
is no evaluation involved, but the description of ++ (6.5.2.4 p2)
says: "See the discussions of additive operators and compound
assignment for information on constraints, types, and /conversions/
[...]" (my emphasis). The description of compound assignment is clear
that, except to the fact that the lvalue E1 is evaluated only once,
E1 += E2 behaves exactly like E1 = E1 + E2.

I think this only matters on "odd" architectures.

The integer promotions are not applied
to the left operand of the assignment operator
in the expression: (E1 = E1 + E2)

That's true, but I must be missing your point since I don't see how
that affects things. The conversions come from the + operator, not
the =.
The type of the left operand,
is the type of the assignment expression.

Again true bit again I don't see what that has to do with my point.
This is why the result of the sizeof is 1, but that matter was settled
several posts ago (at least I though it was).
 
J

James Kuyper

William said:
Keith Thompson wrote:

...


On the other hand, I don't think the standard actually says that an
object can be treated as an array of char, at least not in so many
words. �It's implied by C99 6.2.6.1:
� � Except for bit-fields, objects are composed of contiguous
� � sequences of one or more bytes, the number, order, and encoding of
� � which are either explicitly specified or implementation-defined.
� � ...
� � Values stored in non-bit-field objects of any other object type
� � consist of n * CHAR_BIT bits, where n is the size of an object of
� � that type, in bytes. The value may be copied into an object of
� � type unsigned char [n] (e.g., by memcpy); the resulting set of
� � bytes is called the object representation of the value.
(I've replaced the multiplication symbol by *.)
Note that it talks about *copying* the value into an array of unsigned
char, not treating it in place as if it were an array of unsigned
char. �There's may be other wording that guanttes that the latter will
work as well.
The key point in putting together the inference is the memcpy()
reference. That memcpy() is given only as an example, and not
explicitly stated as being the only way of doing it, implies that
there's nothing magical about memcpy(). In other words, any code which
has the same defined behavior as memcpy() should do the job equally
well. It's perfectly feasible to write ordinary C code that does the
same thing as memcpy(), though not perhaps as efficiently as the built-
in version. Given the definition of memcpy(), it's pretty hard for me
to see how such code could perform such a copy unless the object being
copied could indeed be treated "in place as if it were an array of
unsigned char."

I don't see this at all. It is not even necessary
for memcpy to read the array as char

No, but it is permissible for a user-written equivalent to do so, and
that user-written equivalent must also successfully copy the object.
memcpy() can copy multi-byte objects, not because it has magic
permission to do so, but because the defined behavior of memcpy() has
the result of causing such objects to be copied.
(The array might have to be read in larger chunks)

If were necessary (rather than merely more efficient) to copy the data
in larger chunks, then memcpy() would be the only alternative to
assignment for copying an entire multi-byte object. The standard would
not be able to simply give memcpy() as an example of something that
would do the job, it would have to mandate the use of memcpy() for that job.
And even if we do conclude that this section means that
we must be able to form and dereference a char
pointer that points within the object, the section
says nothing about doing pointer arithmetic
with (char*)(&obj +1)

The following should be (unless I've made some silly mistake), a
strictly conforming C99 function that has the same defined behavior as
memcpy(). Therefore, it should be able to be used to copy multi-byte
objects, just like memcpy(). However, according to your interpretation,
there must be something wrong (undefined behavior?) with the initializer
for pend:

#include <string.h>
void *my_memcpy(
void * restrict s1,
const void * restrict s2,
size_t n
){
unsigned char *p1 = s1;
const unsigned char *p2 = s2;
const unsigned char *pend = p2 + n;

while(p2 < pend)
*p1++ = *p2++;

return s1;
}
 
P

Phil Carmody

Joe Wright said:
Please don't do that again.

The last sentence of the second paragraph of the description
of the sizeof operator says, "If the type of the operand is
a variable length array type, the operand is evaluated;
otherwise, the operand is not evaluated and the result is an
integer constant."

Like others, my first thought was that the behavior was
undefined or implementation defined because of the increment
expression, but that expression is not evaluated.

rot13 is trivial, boring and impolite.

I don't think he did it to challenge us, to exhilarate us, or to
ingraciate himself to us. I think he did it to permit us to not
see his explication, yet know that one was trivially available,
should we want to see it.

Phil
 
T

Tim Rentsch

No. sizeof produces an integer constant expression.

Your emulation does not, preventing use of the value in a case of
a switch statement, for example.

A clarification: the expression ((char*)(&obj+1) - (char*)(&obj))
isn't guaranteed portably to be an integer constant expression,
but it is allowed to be, and indeed it is an ICE on some compilers.
 
T

Tim Rentsch

Keith Thompson said:
[can an object be treated as an array of character type?]

On the other hand, I don't think the standard actually says that an
object can be treated as an array of char, at least not in so many
words. It's implied by C99 6.2.6.1:

Except for bit-fields, objects are composed of contiguous
sequences of one or more bytes, the number, order, and encoding of
which are either explicitly specified or implementation-defined.

...

Values stored in non-bit-field objects of any other object type
consist of n * CHAR_BIT bits, where n is the size of an object of
that type, in bytes. The value may be copied into an object of
type unsigned char [n] (e.g., by memcpy); the resulting set of
bytes is called the object representation of the value.

(I've replaced the multiplication symbol by *.)

Note that it talks about *copying* the value into an array of unsigned
char, not treating it in place as if it were an array of unsigned
char. There's may be other wording that guanttes that the latter will
work as well.

Clearly the standard's authors expect that objects (other than
bit-field objects) can be treated as arrays of character type.
This expectation is evident in normative text, in 6.5p6:

[...] If a value is copied into an object having no declared type
using memcpy or memmove, or is copied as an array of character
type, [...]

(notice that a value is copied /into/ the object, treating it
"as an array of character type"), and also in non-normative
text, in the footnote of 6.5.6p9:

Another way to approach pointer arithmetic is first to convert
the pointer(s) to character pointer(s): In this scheme the
integer expression added to or subtracted from the converted
pointer is first multiplied by the size of the object originally
pointed to, and the resulting pointer is converted back to the
original type. For pointer subtraction, the result of the
difference between the character pointers is similarly divided
by the size of the object originally pointed to.

When viewed in this way, an implementation need only provide one
extra byte (which may overlap another object in the program)
just after the end of the object in order to satisfy the ``one
past the last element'' requirements.

Given these, and also 6.2.6.1p4 and 6.3.2.3p7, it seems pretty
clear: character pointer arithmetic works, successive increments
yield pointers to successive bytes of the object, implementations
"need only provide one extra byte" (to account for pointing one past
the object or its character array), and objects can be accessed "as
an array of character type". Does any reasonable doubt remain?
 
T

Tim Rentsch

William Hughes said:
[must objects be accessible as arrays of character type]

I don't see this at all. It is not even necessary
for memcpy to read the array as char
(The array might have to be read in larger chunks)
And even if we do conclude that this section means that
we must be able to form and dereference a char
pointer that points within the object, the section
says nothing about doing pointer arithmetic
with (char*)(&obj +1)

In addition to 6.2.6.1p4, please see 6.3.2.3p7, 6.5p6,
and 6.5.6p9 (including the footnote). Note that 6.5p6
talks about copying a value into an object "as an array
of character type" (and specifically not using memcpy()).
Wouldn't you say the standard's authors expect that
objects must be able to be treated as character arrays?
 

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,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top