Size of Stucture without sizeof()

C

Christian Bau

Krishanu Debnath said:
Richard said:
Suman said:
Santhosh wrote:
All the major contributors to clc have said that any approach to do
what OP asked without using sizeof is silly.
[...]
printf("%u\n", (char *)(ptr+1) - (char *)ptr);
Its not silly.Its plain UB.

Is it? Yes, if size_t is not an unsigned int, but that's hardly
relevant, is it? If we correct that, how is this UB?

printf("%lu\n", (unsigned long) ((char *)(ptr+1)-(char *)ptr));

Richard

What it has to do with size_t or unsigned type? Pointer subtraction
gives you value of type ptrdiff_t which is signed integer type.

If size_t is not unsigned int, then ptrdiff_t is not int, and then the
format %u is incorrect (it is not strictly correct for outputting int,
but it is ok for positive values as in this case).
 
K

Krishanu Debnath

Christian said:
Krishanu Debnath said:
Richard said:
Santhosh wrote:
All the major contributors to clc have said that any approach to do
what OP asked without using sizeof is silly.
[...]
printf("%u\n", (char *)(ptr+1) - (char *)ptr);
Its not silly.Its plain UB.
Is it? Yes, if size_t is not an unsigned int, but that's hardly
relevant, is it? If we correct that, how is this UB?

printf("%lu\n", (unsigned long) ((char *)(ptr+1)-(char *)ptr));

Richard
What it has to do with size_t or unsigned type? Pointer subtraction
gives you value of type ptrdiff_t which is signed integer type.

If size_t is not unsigned int, then ptrdiff_t is not int, and then the

Can you please provide C&V to prove your assertion? I am unable to find
it. Thanks.
format %u is incorrect (it is not strictly correct for outputting int,
but it is ok for positive values as in this case).

Krishanu
 
R

Richard Bos

Niklas Norrthon said:
[obscure discussion snipped]
Then I was *too* obscure. I was intending to imply that you don't need an
array at all. Or have I missed something? Or should we defer this
discussion until the OP's deadline has probably passed?

Supposing this is a homework assignment, is there anyone out there
who could give one single reason why an instructor would give such
an assignment to his students?

Incompetence and laziness.
What points could be illustrated by such hacks? Pointer arithmetics?

_Poor_ pointer arithmetics. There are better ways to illustrate the
feature in question.

Richard
 
J

Jordan Abel

No. Nor is that meaningful. That's what sizeof is *for*. Various unportable
tricks suggest themselves as replacements, all of them worthless because
they're unportable tricks when a perfectly portable alternative is
available: sizeof.

If this is a homework assignment, tell the instructor to come up with better
questions.

struct something foo;

[sizeof foo ==] (unsigned char *)(&foo+1)-(unsigned char *)(&foo)

what's unportable about this?

[using NULL for this purpose is the unportable trick i assume you refer
to, but using a temporary gets rid of that issue.]
 
J

Jordan Abel

Richard said:
Suman said:
Santhosh wrote:
All the major contributors to clc have said that any approach to do
what OP asked without using sizeof is silly.
[...]
printf("%u\n", (char *)(ptr+1) - (char *)ptr);
Its not silly.Its plain UB.

Is it? Yes, if size_t is not an unsigned int, but that's hardly
relevant, is it? If we correct that, how is this UB?

printf("%lu\n", (unsigned long) ((char *)(ptr+1)-(char *)ptr));

Richard

What it has to do with size_t or unsigned type? Pointer subtraction
gives you value of type ptrdiff_t which is signed integer type.

Krishanu

And in this case it is known to be positive, and thus it is safe to cast
it to an unsigned type. Given the use of an unsigned type, even overflow
can't cause UB.
 
S

Skarmander

Jordan said:
No. Nor is that meaningful. That's what sizeof is *for*. Various unportable
tricks suggest themselves as replacements, all of them worthless because
they're unportable tricks when a perfectly portable alternative is
available: sizeof.

If this is a homework assignment, tell the instructor to come up with better
questions.

struct something foo;

[sizeof foo ==] (unsigned char *)(&foo+1)-(unsigned char *)(&foo)

what's unportable about this?

[using NULL for this purpose is the unportable trick i assume you refer
to, but using a temporary gets rid of that issue.]

Using a temporary makes it impossible to write a sizeof() that is
syntactically equivalent (for structs, at least), since you cannot declare
temporaries in macros that expand to expressions and you cannot write
functions that take type names.

I'll grant you that the original question only talked about "knowing" the
size of "a" structure, which allows for much leeway. And in all likelihood,
we have successfully done the OP's homework by now.

S.
 
K

Keith Thompson

Niklas Norrthon said:
[obscure discussion snipped]
Then I was *too* obscure. I was intending to imply that you don't need an
array at all. Or have I missed something? Or should we defer this
discussion until the OP's deadline has probably passed?

Supposing this is a homework assignment, is there anyone out there
who could give one single reason why an instructor would give such
an assignment to his students? What points could be illustrated
by such hacks? Pointer arithmetics?

Determining the size of a structure without "sizeof" is a dumb thing
to do in real life. Being *able* to determine the size of a structure
without sizeof is a reasonable way to demonstrate some knowledge of
the language, which is the point of homework after all. (The ugliness
of the solution also helps illustrate why "sizeof" is in the
language.)

The classic "Hello, world" program is not useful by itself. If
printing "Hello, world" is really the goal, there are generally easier
ways to do it (such as "echo Hello, world", depending on the
environment). The point is to demonstrate the use of the language.
 
M

Mark McIntyre

Can you please provide C&V to prove your assertion? I am unable to find
it. Thanks.

C&V not required, just logic. Think it through in terms of two
pointers differing in location by sizeof(typeof(size_t))
 
F

Flash Gordon

Artie said:

Small additional point. Why do you need an additional byte seeing as
there is one exception to pointer arithmetic staying within an object? :)
 
K

Keith Thompson

Flash Gordon said:
Small additional point. Why do you need an additional byte seeing as
there is one exception to pointer arithmetic staying within an object?
:)

(Referring to constructing, but not dereferencing, a pointer just past
the end of an array object.)

The Rationale says:

An important endorsement of widespread practice is the requirement
that a pointer can always be incremented to just past the end of
an array, with no fear of overflow or wraparound:

[example snipped]

This stipulation merely requires that every object be followed by
one byte whose address is representable. That byte can be the
first byte of the next object declared for all but the last object
located in a contiguous segment of memory.

I think the Rationale doesn't quite get this right. The standard
guarantees that you can construct a pointer just past the end of an
array; this doesn't necessarily require the existence of a byte at
that location. If it did, the following would (presumably) be valid:

char arr[10];
char *ptr = arr+9;
ptr++;
*ptr; /* accessing the mythical extra byte */

Some systems might have to allocate a byte at that location in order
to make "ptr++" work correctly, but others don't. For example, arr
might happen to occupy the last 10 bytes of phyical memory; it could
still be possible to construct an address that doesn't point to any
actual memory, either physical or virtual.

IMHO, the Rationale should refer to something like "one byte (possibly
nonexistent) whose address is representable".
 
F

Flash Gordon

Mark said:
C&V not required, just logic. Think it through in terms of two
pointers differing in location by sizeof(typeof(size_t))

Undefined behaviour is the subtraction results in a value outside the
range of ptrdiff_t.

How about an implementation where size_t is unsigned short and ptrdiff_t
is int? I'm not saying this would be sensible, but is it allowed?

Also, since the standard says that pointer subtraction does not have to
yield a result within the range of ptrdiff_t (and behaviour is undefined
if it does not) I would have thought that having ptrdiff_t being int and
size_t being unsigned long was legal if not sensible. Unless you can
find something in the standard that actually puts some requirements
(beyond minimum range, which is -65535 to +65535).
 
J

Jordan Abel

Undefined behaviour is the subtraction results in a value outside the
range of ptrdiff_t.

How about an implementation where size_t is unsigned short and ptrdiff_t
is int? I'm not saying this would be sensible, but is it allowed?

Also, since the standard says that pointer subtraction does not have to
yield a result within the range of ptrdiff_t (and behaviour is undefined
if it does not) I would have thought that having ptrdiff_t being int and
size_t being unsigned long was legal if not sensible. Unless you can
find something in the standard that actually puts some requirements
(beyond minimum range, which is -65535 to +65535).

IIRC A strictly conforming program won't contain pointer arithmetic
whose result will fall outside that range, since that would require
exceeding the minimum maximum object size. [actually, a result of
+-65536 might be possible as a pathological case, i'm not sure.]
 
M

Mark B

Christian Bau said:
Santhosh said:
All the major contributors to clc have said that any approach to do
what OP asked without using sizeof is silly. I just want to understand
in what ways the following piece of code can give incorrect result in
some common general purpose programming environments ? (pls, lets
ignore obscure architectures which still supports C)

Your code was fine, it is just silly not to use sizeof ().

Now try this struct:

typedef struct {
char a [2000000000];
double d;
} mystruct;

and see what your program does.

I'm missing your point...
my compilers can't build a program with your 'silly' struct :)
What does that have to do with the code in question?
 
J

Jordan Abel

Christian Bau said:
Santhosh said:
All the major contributors to clc have said that any approach to do
what OP asked without using sizeof is silly. I just want to understand
in what ways the following piece of code can give incorrect result in
some common general purpose programming environments ? (pls, lets
ignore obscure architectures which still supports C)

Your code was fine, it is just silly not to use sizeof ().

Now try this struct:

typedef struct {
char a [2000000000];
double d;
} mystruct;

and see what your program does.

I'm missing your point... my compilers can't build a program with
your 'silly' struct :) What does that have to do with the code in
question?

I think he thinks that it's somehow useful to be able to take the size
of a type that you can't declare an instance of.
 
F

Flash Gordon

Keith said:
(Referring to constructing, but not dereferencing, a pointer just past
the end of an array object.)

I knew, of course, that you were allowed to generate the address and use
it in pointer arithmetic. It was merely that there had to be a byte I
queried. e.g. I was thinking that on a machine without virtual memory
for one object the address could be one beyond the end of physical
memory, so you could argue there was no byte although there was an address.
The Rationale says:

An important endorsement of widespread practice is the requirement
that a pointer can always be incremented to just past the end of
an array, with no fear of overflow or wraparound:

[example snipped]

This stipulation merely requires that every object be followed by
one byte whose address is representable. That byte can be the
first byte of the next object declared for all but the last object
located in a contiguous segment of memory.

I think the Rationale doesn't quite get this right. The standard
guarantees that you can construct a pointer just past the end of an
array; this doesn't necessarily require the existence of a byte at
that location.

The rational only says the bytes address needs to be representable, not
that the byte actually needs to be accessible.
> If it did, the following would (presumably) be valid:

<snip stuff where I agree with Keith.
IMHO, the Rationale should refer to something like "one byte (possibly
nonexistent) whose address is representable".

I agree that would be better.
 
S

Skarmander

Jordan said:
Christian Bau said:
All the major contributors to clc have said that any approach to do
what OP asked without using sizeof is silly. I just want to understand
in what ways the following piece of code can give incorrect result in
some common general purpose programming environments ? (pls, lets
ignore obscure architectures which still supports C)
Your code was fine, it is just silly not to use sizeof ().

Now try this struct:

typedef struct {
char a [2000000000];
double d;
} mystruct;

and see what your program does.
I'm missing your point... my compilers can't build a program with
your 'silly' struct :) What does that have to do with the code in
question?

I think he thinks that it's somehow useful to be able to take the size
of a type that you can't declare an instance of.

Rather, that it could be useful to know the size of a structure without
needing to declare an instance, even if you are capable of doing so, if for
example the structure is very large, or there are many such structures you
need to know the size of, or you need an integer constant expression (which
only sizeof can provide). This is not unreasonable, but unlikely to be of
significance for the original question.

S.
 
M

Mark McIntyre

Undefined behaviour is the subtraction results in a value outside the
range of ptrdiff_t.

Not relevant to the original question.
How about an implementation where size_t is unsigned short and ptrdiff_t
is int? I'm not saying this would be sensible, but is it allowed?

Probably. I assumed the original point was that ptrdiff_t had to be at
least big enough, rather than that one was disallowed from creating
absurd implementations.
 
F

Flash Gordon

Mark said:
Not relevant to the original question.


Probably. I assumed the original point was that ptrdiff_t had to be at
least big enough, rather than that one was disallowed from creating
absurd implementations.

I misread who stated what, sorry. I was supporting the proposition that
ptrdiff_t does not have to be large enough. I agree that the statement
by Christian:is not required to be true, and I was supporting the proposition that it
is not required to be true by the standard.
 
J

Jack Klein

All the major contributors to clc have said that any approach to do
what OP asked without using sizeof is silly. I just want to understand
in what ways the following piece of code can give incorrect result in
some common general purpose programming environments ? (pls, lets
ignore obscure architectures which still supports C)

#include<stdio.h>
int main() {
struct tag {
int a;
char b;
float c;
}tag;

struct tag *ptr = &tag;

printf("%u\n", (char *)(ptr+1) - (char *)ptr);

Undefined behavior, because even though ptrdiff_t is an
implementation-defined type, it is a signed type and therefore can't
be an unsigned int suitable for the "%u" conversion specifier. And it
might be larger than int.
}
%

thanks,
Santhosh.

The other problem, which does not exist with this example, but what if
the size of the object is larger than the maximum value that a
ptrdiff_t can hold? An object can't contain more than size_t bytes,
but there is no prohibition in the standard from one containing more
bytes than the maximum value of a ptrdiff_t, which is a signed type.
 

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,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top