Sizeof query

P

Praveen Raj

Sir, Is this emulation of sizeof is valid..??

size_t sizeof_obj = (char*)(&obj + 1) - (char*)(&obj);

Standard says
A pointer to an object or incomplete type may be converted to a
pointer to a different object or incomplete type. If the resulting
pointer is not correctly aligned for the pointed-to type, the behavior
is undefined.

and
When a pointer to an object is converted to a pointer to a character
type, the result points to the lowest addressed byte of the object.
Successive increments of the result, up to the size of the object,
yield pointers to the remaining bytes of the object.

+

If two pointers to objects of the same type are subtracted, the result
is a signed integral value representing the displacement between the
pointed-to objects; pointers to successive objects differ by 1. The
type of the result is defined as ptrdiff_t in the standard header
<stddef.h>. The value is undefined unless the pointers point to
objects within the same array; however, if P points to the last member
of an array, then (P+1)-P has value 1..
 
A

Alan Curry

Sir, Is this emulation of sizeof is valid..??

size_t sizeof_obj = (char*)(&obj + 1) - (char*)(&obj);

The only chance for it to go wrong is if the object is bigger than the
maximum value of ptrdiff_t. Even then, there's a fairly good chance that the
correct result will appear, after the signed result overflows negative, and
the negative value is reinterpreted as unsigned when you convert it to
size_t.

Trying to test that idea, I found that gcc won't let me declare anything that
big. Not even if I make it extern, and don't define it anywhere. Or even if I
make it part of a struct, and then don't declare any instances of the struct.

The question on everyone's mind will be:
Is there a reason for emulating sizeof?
 
P

Praveen Raj

The only chance for it to go wrong is if the object is bigger than the
maximum value of ptrdiff_t. Even then, there's a fairly good chance that the
correct result will appear, after the signed result overflows negative, and
the negative value is reinterpreted as unsigned when you convert it to
size_t.

Trying to test that idea, I found that gcc won't let me declare anything that
big. Not even if I make it extern, and don't define it anywhere. Or even if I
make it part of a struct, and then don't declare any instances of the struct.

The question on everyone's mind will be:
Is there a reason for emulating sizeof?

That is a common question asked by companies in there interview's..
:)
 
R

Richard Tobin

Richard Heathfield said:
The best answer you can give is: "I would use sizeof. That's what it's
/for/. And it's guaranteed to be available, even in freestanding
implementations."

I'm baffled as to why you think this is such a bad question.
Obviously it's not intended to imply that sizeof() might really be
unavailable. I think it's actually a rather good question, because it
tests the candidate's understanding of C rather than his ability to
regurgitate stuff. It also has the potential for useful followup
questions such as "is it affected by padding between the two array
elements".

Of course, its wide circulation on Usenet rather devalues it, but
provided the candidate can explain it rather than just reproduce it
then I think it still works.

-- Richard
 
J

jameskuyper

Gordon said:
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.

For that matter, it doesn't work with type names, either.
 
F

Flash Gordon

Richard said:
Kenneth Brody said:
Richard said:
Praveen Raj wrote:

On Sep 15, 3:30 pm, (e-mail address removed) (Alan Curry) wrote:
<snip>

The question on everyone's mind will be:
Is there a reason for emulating sizeof?
That is a common question asked by companies in there
interview's..
:) [...]
And if you're feeling suicidal, you can ask the interviewer: "what
is the return type of main?" I did this once, right at the
beginning of the interview. The interviewer answered correctly
(well done, John!),
The Standard defines it as int. However, it is also allowed to be
any "implementation-defined" type as well, thereby allowing "void
main(void)" to be perfectly valid on any given implementation, if
the implementor so desires.

Do I pass? :)

Well, you didn't get anything wrong, but it may have been as well to
add: "...but such usage is clearly not portable to all
implementations".
However, 5.1.2.2.1 doesn't explicitly say that, if an implementation
has main() defined in "some other implementation-defined manner",
can the implementation disallow the two forms listed by the
Standard?

A freestanding implementation can have whatever entry point (point at
which control flow enters user code) it likes. If your Acme GreenNose
automatic mobile cheese grater's C compiler decides to make its entry
point void scratchnsniff(void), well, dem's de breaks.
If I were an interviewer and was feeling a bit "evil", I might ask
for the output of the following program when compiled and run on an
EBCDIC system:

#include <stdio.h>

int main(void)
{
char new = 'z';

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

return(0);
}

<previous answer, along the lines of "what's evil about it?", deleted>

Ah, the penny just dropped. Yes, okay, that's evil.

Gur rivy gjvfg vf, bs pbhefr, gung gur jubyr ropqvp guvat vf n pnaneq.
Ohg na vagreivrjrr jbhyq unir gb *xabj* gung gur punenpgre frg znxrf
ab qvssrerapr va beqre gb evfx nafjrevat gung jnl.

That's a GOOD evil twist.

Yes, my initial answer (until I read the code) would have been gung V
qba'g xabj ROPQVP. Nf fbba nf V ernq gur pbqr, ubjrire, gur boivbhf naq
pbeerpg zvavzny nafjre vf gung vg vf vzcyrzragngvba qrsvarq, ohg will be
implementation defined.
 
S

Seebs

For extra credit:

What if you change the sizeof to sizeof(int a[new++])?

(Assume C99.)

-s
 
K

Keith Thompson

Seebs said:
For extra credit:

What if you change the sizeof to sizeof(int a[new++])?

(Assume C99.)

A syntax error message from the compiler. ``int a[new++]''
is a declaration, not an expression.

I think you mean ``sizeof(int[new++])''.
 
K

Keith Thompson

Flash Gordon said:
Seebs said:
On 2009-09-15 said:
#include <stdio.h>

int main(void)
{
char new = 'z';

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

return(0);
}

For extra credit:

What if you change the sizeof to sizeof(int a[new++])?

(Assume C99.)

Undefined behaviour.

You mean after the required diagnostic for the syntax error?
 
S

Seebs

For extra credit:

What if you change the sizeof to sizeof(int a[new++])?

(Assume C99.)

A syntax error message from the compiler. ``int a[new++]''
is a declaration, not an expression.

I think you mean ``sizeof(int[new++])''.

Yup.

(You can see that I'm mostly back here because I've gotten rusty.)

-s
 
B

Ben Bacarisse

Keith Thompson said:
Seebs said:
On 2009-09-15 said:
#include <stdio.h>

int main(void)
{
char new = 'z';

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

return(0);
}

For extra credit:

What if you change the sizeof to sizeof(int a[new++])?

(Assume C99.)

A syntax error message from the compiler. ``int a[new++]''
is a declaration, not an expression.

I think you mean ``sizeof(int[new++])''.

This is really just tidying things up in case anyone is a little
confused by this. A reader might erroneously conclude that your
correction replaces the declaration with something that *is* an
expression.

It might have been clearer to say that ``int a[new++]'' is a
declaration, not a type name, since that is what you supply as the
correction. Of course an expression (specifically a unary expression)
is also permitted after sizeof, but only the oldest quoted code uses
that syntax.
 
M

Morris Keesan

Sir, Is this emulation of sizeof is valid..??

size_t sizeof_obj = (char*)(&obj + 1) - (char*)(&obj);

No. It's likely to work on many implementations, but as the part of the
standard you quote says,
The value is undefined unless the pointers point to
objects within the same array; however, if P points to the last member
of an array, then (P+1)-P has value 1..

Unless obj is the last member of an array, the value of sizeof_obj is
undefined.

Furthermore, the C99 standard (which is not the one you quoted; I don't
have my
hardcopy of the C90 standard available, but I assume that's what you're
looking at)
says in 6.5.6p8

If both the pointer operand and the result point to elements of the
same array object, or one past the last element of the array object,
the evaluation shall not produce an overflow; otherwise, the
behavior is undefined.

So the expression (&obj + 1) invokes undefined behavior unless obj is a
member of an array, even without the pointer subtraction.

The next paragraph of C99 says, "When two pointers are subtracted, both
shall
point to elements of the same array object, or one past the last element of
the array object;
 
M

Morris Keesan

If I were an interviewer and was feeling a bit "evil", I might ask for
the output of the following program when compiled and run on an EBCDIC
system:

#include <stdio.h>

int main(void)
{
char new = 'z';

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

return(0);
}

This one is very cute, and has tripped up at least two experts responding
to it. In fact, the output is well-defined, invoking no implementation-
defined or undefined behavior.

Gur ynfg fragrapr bs gur frpbaq cnentencu bs gur qrfpevcgvba
bs gur fvmrbs bcrengbe fnlf, "Vs gur glcr bs gur bcrenaq vf
n inevnoyr yratgu neenl glcr, gur bcrenaq vf rinyhngrq;
bgurejvfr, gur bcrenaq vf abg rinyhngrq naq gur erfhyg vf na
vagrtre pbafgnag."

Yvxr bguref, zl svefg gubhtug jnf gung gur orunivbe jnf
haqrsvarq be vzcyrzragngvba qrsvarq orpnhfr bs gur vaperzrag
rkcerffvba, ohg gung rkcerffvba vf abg rinyhngrq.
 
K

Keith Thompson

Morris Keesan said:
No. It's likely to work on many implementations, but as the part of the
standard you quote says,


Unless obj is the last member of an array, the value of sizeof_obj is
undefined.

Ah, but you've missed the key passage. C99 6.5.6p7, in the discussion
of additive operators, says:

For the purposes of these operators, a pointer to an object that
is not an element of an array behaves the same as a pointer to
the first element of an array of length one with the type of
the object as its element type.

C90 has similar wording.

[snip]
 
S

Seebs

No. It's likely to work on many implementations, but as the part of the
standard you quote says,


Unless obj is the last member of an array, the value of sizeof_obj is
undefined.

An object is, for purposes of that, equivalent to an array of one object,
so "&obj+1" is a defined value which would be the address of the next
object if there were an array of them.
So the expression (&obj + 1) invokes undefined behavior unless obj is a
member of an array, even without the pointer subtraction.

See paragraph 7:
For the purposes of these operators, a pointer to an object that
is not an element of an array behaves the same as a pointer to the
first element of an array of length one with the type of the object
as its element type.

-s
 
M

Morris Keesan

Ah, but you've missed the key passage. C99 6.5.6p7, in the discussion
of additive operators, says:

For the purposes of these operators, a pointer to an object that
is not an element of an array behaves the same as a pointer to
the first element of an array of length one with the type of
the object as its element type.

Oops. Yes, I have, and yes, it does. That's what I get for not reading
*all* of a section.

Never mind.
 
K

Keith Thompson

Joe Wright said:
Morris Keesan wrote: [...]
Gur ynfg fragrapr bs gur frpbaq cnentencu bs gur qrfpevcgvba
bs gur fvmrbs bcrengbe fnlf, "Vs gur glcr bs gur bcrenaq vf
n inevnoyr yratgu neenl glcr, gur bcrenaq vf rinyhngrq;
bgurejvfr, gur bcrenaq vf abg rinyhngrq naq gur erfhyg vf na
vagrtre pbafgnag."

Yvxr bguref, zl svefg gubhtug jnf gung gur orunivbe jnf
haqrsvarq be vzcyrzragngvba qrsvarq orpnhfr bs gur vaperzrag
rkcerffvba, ohg gung rkcerffvba vf abg rinyhngrq.
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.

rot13 is a perfectly legitimate way to discuss something without
spoiling it for others who might want to figure it out for themselves.
 
A

Alan Curry

#include <stdio.h>

int main(void)
{
char new = 'z';

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

return(0);
}

The hard part being, of course, remembering what sort of automatic
conversions apply to new++

I seem to recall these being defined in various circumstances:

usual arithmetic conversions
integer promotions
default argument promotions
default maze of promotion
usual twisty conversions

....all different.

Now will one of those result in new++ being an int? It means new=new+1, and
the 1 is an int. Something could happen.

Before running the code, I guessed correctly. But I have a feeling it was
because there were a pair of hidden conversions that cancelled each other
out, not because there were no hidden conversions at all.
 
N

Nick Keighley

That is a common question asked by companies in there interview's..

great! So now you know the answer!

"no, there is no good reason for emulating the behaviour of sizeof"
 

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,011
Latest member
AjaUqq1950

Latest Threads

Top