sizeof(struct dirent.d_ino)

M

Martin Pohlack

Hi,

I have a funtion which shall compute the amount for a later malloc. In
this function I need the sizes of some struct members without having an
instance or pointer of the struct.

As "sizeof(int)" is legal I assumed "sizeof(struct x.y)" to be legal
too. But is is not:

#include <dirent.h>

int dir_dirent_size(dir_t * dirp)
{
int len;

// syntax error
len = sizeof(struct dirent.d_ino) +
sizeof(struct dirent.d_off) +
sizeof(struct dirent.d_reclen) +
strlen(dirp->name) + 1;

return len;
}


I can fix this problem using a dummy pointer to a dirent struct:

#include <dirent.h>

int dir_dirent_size(dir_t * dirp)
{
int len;
struct dirent * temp;

// syntax error
len = sizeof(temp.d_ino) +
sizeof(temp.d_off) +
sizeof(temp.d_reclen) +
strlen(dirp->name) + 1;

return len;
}


However, I'm curious what would be the 'right thing' (tm) to do.

Thank you,
Martin Pohlack
 
I

Irrwahn Grausewitz

Martin Pohlack said:
Hi,

I have a funtion which shall compute the amount for a later malloc. In
this function I need the sizes of some struct members without having an
instance or pointer of the struct.

As "sizeof(int)" is legal I assumed "sizeof(struct x.y)" to be legal
too. But is is not:

#include <dirent.h>

int dir_dirent_size(dir_t * dirp)
{
int len;

// syntax error
len = sizeof(struct dirent.d_ino) +
sizeof(struct dirent.d_off) +
sizeof(struct dirent.d_reclen) +
strlen(dirp->name) + 1;

return len;
}


I can fix this problem using a dummy pointer to a dirent struct:

#include <dirent.h>

This is a non-standard header. Anyway, I suppose it declares
(at least) the struct dirent you are referring to later...
int dir_dirent_size(dir_t * dirp)
{
int len;
struct dirent * temp;

// syntax error
len = sizeof(temp.d_ino) +
sizeof(temp.d_off) +
sizeof(temp.d_reclen) +
strlen(dirp->name) + 1;

return len;
}


However, I'm curious what would be the 'right thing' (tm) to do.

You should change the above to:

len = sizeof temp->d_ino +
sizeof temp->d_off +
sizeof temp->d_reclen +
...

as temp is a *pointer* to a struct and the parantheses are optional,
when applying the sizeof operator to an object, not a type.

Further more, if your intention is to calculate the size of the /whole/
struct, inclusive possible padding, you should just write:

len = sizeof *temp +
...

Regards,

Irrwahn
 
M

Martin Pohlack

First of all, thank you for your answer.

Irrwahn said:
This is a non-standard header. Anyway, I suppose it declares (at
least) the struct dirent you are referring to later...


yes, the struct is declared there, but that should not be important for
my example. Anyway, the struct looks like follows:

struct dirent
{
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[256];
};

You should change the above to:

len = sizeof temp->d_ino + sizeof temp->d_off + sizeof temp->d_reclen
+ ...

as temp is a *pointer* to a struct and the parantheses are optional,
when applying the sizeof operator to an object, not a type.


yes, you are right. I must confess I constructed the example without of
trying to recompile it after the last changes. So, what you wrote is
what I head in mind ;-). However, optional is not the same as forbidden.
So I consider the question of parantheses as a question of style.

Further more, if your intention is to calculate the size of the
/whole/ struct, inclusive possible padding, you should just write:

len = sizeof *temp + ...


Yes, of course that is what I *would* do. But I don't want that.

I want to compute the size of *parts* of the struct *without* of having
an instance of it, as it is possible to compute the size of an int by
writing:

x = sizeof(int);

On the contrary it is possible to do it with an instance:


int a;
x = sizeof(x);

or

int *a;
x = sizeof(*a);

For more complex types it only seems to be possible to use one of the
last cases.

Or is there a way???


btw. a (local) friend of mine suggested the following:

len = sizeof (((struct dirent *) 0)->d_ino);


greets,
Martin
 
M

Martin Dickopp

Martin Pohlack said:
I want to compute the size of *parts* of the struct *without* of having
an instance of it,

Why?

If your only concern is wasted space, I wouldn't worry about it. An
instance of a structure which is not used except that its members are
operands to the `sizeof' operator is likely to be optimized away by
the compiler.

If you have another reason, read on...
btw. a (local) friend of mine suggested the following:

len = sizeof (((struct dirent *) 0)->d_ino);

This causes undefined behavior. However, you could use the `offsetof'
macro (defined in <stddef.h>) which yields the offset of a structure
member from the beginning of the structure. If you have, for example,

struct foo {
int bar;
long baz;
float blah;
double blub;
void *platsch;
};

then the expression

offsetof (struct foo, blub) - offsetof (struct foo, blah)

yields the size of `blah', and

sizeof (struct foo) - offsetof (struct foo, platsch)

yields the size of `platsch'.

Martin
 
U

Udo A. Steinberg

On 08 Sep 2003 23:23:33 +0200 Martin Dickopp (MD) wrote:

Hi,

MD> If your only concern is wasted space, I wouldn't worry about it. An
MD> instance of a structure which is not used except that its members are
MD> operands to the `sizeof' operator is likely to be optimized away by
MD> the compiler.

Agreed.

MD> > len = sizeof (((struct dirent *) 0)->d_ino);
MD>
MD> This causes undefined behavior.

Can you elaborate on why this is undefined behaviour? It is implemented
in a similar manner to the offsetof macro.

MD> offsetof (struct foo, blub) - offsetof (struct foo, blah)
MD>
MD> yields the size of `blah', and

Tricks like this rely on the order of structure members being known and
never changing which is why we considered it sub-optimal.

-Udo.
 
I

Irrwahn Grausewitz

Martin Pohlack said:
However, optional is not the same as forbidden.
So I consider the question of parantheses as a question of style.
Agreed.

I want to compute the size of *parts* of the struct *without* of having
an instance of it
I have to accept that that's what you want, but may I ask what's so
terrible on having an instance of, or, at least, a pointer to the type
you want to know the size of? What's the reason for the restriction?

int a;
x = sizeof(x);
^^^
That's hopefully just a typo... :^)

btw. a (local) friend of mine suggested the following:

len = sizeof (((struct dirent *) 0)->d_ino);
Hm, this looks like a legal C construct, as it does not dereference
the NULL pointer AFAICS, but I'm not among the experts, so maybe I'm
terribly wrong on this...

Irrwahn
 
M

Mark Gordon

On 08 Sep 2003 23:23:33 +0200 Martin Dickopp (MD) wrote:

Hi,

MD> If your only concern is wasted space, I wouldn't worry about it.
MD> An instance of a structure which is not used except that its
MD> members are operands to the `sizeof' operator is likely to be
MD> optimized away by the compiler.

Agreed.

MD> > len = sizeof (((struct dirent *) 0)->d_ino);
MD>
MD> This causes undefined behavior.

Can you elaborate on why this is undefined behaviour? It is
implemented in a similar manner to the offsetof macro.

The implementation is allowed to use any non-standard tricks it like in
the headers it provides since those headers are only for that
implementation. It could even have special magic in the compiler to make
those headers work without making the same tricks work in user generated
code.

In the example above the null pointer is being dereferenced so it is
undefined behaviour in any code you write.

You could always use something like
{
struct dirent dummy;
len = sizeof dummy.d_ino;
}

I would not expect any decent compiler to allocate space for dummy.
MD> offsetof (struct foo, blub) - offsetof (struct foo, blah)
MD>
MD> yields the size of `blah', and

Tricks like this rely on the order of structure members being known
and never changing which is why we considered it sub-optimal.

It also has the potential to give a different result since there might
be padding between the end of blah and the start of blub and does not
work for the last element since there is no member after it.
 
M

Martin Dickopp

Udo A. Steinberg said:
MD> > len = sizeof (((struct dirent *) 0)->d_ino);
MD>
MD> This causes undefined behavior.

Can you elaborate on why this is undefined behaviour?

Standard section 6.5.2.3#4 defines the behavior of the `->' operator
only for the case that the left operand points to an object, which a
null pointer of type `struct dirent *' does not. Section 4#2 makes it
clear that whenever no behavior is defined explicitly, the behavior
is undefined.
It is implemented in a similar manner to the offsetof macro.

The standard doesn't define how the `offsetof' is implemented.

Many C implementations do in fact apply the `->' operator to a null
pointer of appropriate type, but that doesn't mean it's also valid in
user code. :) The language implementor knows what extensions his
implementation supports and is therefore not bound by the standard.
In fact, I don't think there's any portable way to achive the effect
of the `offsetof' macro without actually using it.
MD> offsetof (struct foo, blub) - offsetof (struct foo, blah)
MD>
MD> yields the size of `blah', and

Tricks like this rely on the order of structure members being known and
never changing which is why we considered it sub-optimal.

I agree. Which brings me back to the question of what you (or rather the
OP, but you seem to be affiliated with the same TUD institute, so can I
assume you work on the same thing?) are trying to achieve?

Martin
 
M

Martin Dickopp

Irrwahn Grausewitz said:
Hm, this looks like a legal C construct, as it does not dereference
the NULL pointer AFAICS,

It doesn't dereference the null pointer, since the operand of the `sizeof'
operator is not evaluated. But according to my understanding of the
standard, the behavior is still undefined. See my other posting in this
thread.

Martin
 
M

Martin Dickopp

Mark Gordon said:
In the example above the null pointer is being dereferenced so it is
undefined behaviour in any code you write.

I don't think the null pointer is dereferenced, as the operand of the
`sizeof' operator is not evaluated. I believe it to be undefined behavior
because the standard only defines the behavior of `->' when its left
operand points to an object (6.5.2.3#4).
It also has the potential to give a different result since there might
be padding between the end of blah
Correct.

and the start of blub and does not work for the last element since there
is no member after it.

But there /is/ a member after the last one - don't you see it? ;)
Its offset from the beginning of the structure is `sizeof (struct foo)'.

Martin
 
J

Jack Klein

Why?

If your only concern is wasted space, I wouldn't worry about it. An
instance of a structure which is not used except that its members are
operands to the `sizeof' operator is likely to be optimized away by
the compiler.

If you have another reason, read on...


This causes undefined behavior.

No, it does not. In fact it is perfectly well defined, because the
sizeof operator is evaluated at compile time based on the type of the
operand and does not evaluate at run time at all.

OK, C99 has added an exception, sizeof applied to a variable length
array will (because it must) be evaluated at run time, but that does
not apply here.
However, you could use the `offsetof'
macro (defined in <stddef.h>) which yields the offset of a structure
member from the beginning of the structure. If you have, for example,

struct foo {
int bar;
long baz;
float blah;
double blub;
void *platsch;
};

then the expression

offsetof (struct foo, blub) - offsetof (struct foo, blah)

yields the size of `blah', and

sizeof (struct foo) - offsetof (struct foo, platsch)

yields the size of `platsch'.

Martin

Absolutely nothing wrong with recommending offsetof, of course.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
J

Jack Klein

It doesn't dereference the null pointer, since the operand of the `sizeof'
operator is not evaluated. But according to my understanding of the
standard, the behavior is still undefined. See my other posting in this
thread.

Martin

Nope, it's not, honest. It's been beaten to death a few times in
comp.std.c. Try a google search there.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
M

Martin Pohlack

Martin said:

I'm actually implementing some kind of fileserver, using a posix like
interface (open, close, read, write, ...). For directory handling I had
a look at the 'getdents()' systemcall of linux, which reads as follows:

int getdents(unsigned int fd, struct dirent *dirp, unsigned int count);

One might want to use this call to get some entries out of an openened
(fd) directory. dirp is filled with up to count bytes.

Using the structure dirent:

struct dirent
{
long d_ino; /* inode number */
off_t d_off; /* offset to next dirent */
unsigned short d_reclen; /* length of this dirent */
char d_name [NAME_MAX+1]; /* file name (null-terminated) */
}

What is returned by this syscall is *not* an array of such structs, but
it is rather compressed. As the name of the entry is the last member,
its trailing bytes (after the \0) are ommited. The start of the next
struct may be computed using the d_reclen, which hold the lenght of the
actual entry in bytes, d_off seems not to work as it contains illegal
values sometimes.

In my fileserver, directories are stored in a completely different
format, so I have to convert them. To actually allocate the necessary
buffersize I added the effective (read: with shortened names) lenghts of
the directory entries.

As it looks now, the best solution seems to be to use the offset of
d_name in the struct and at runtime add the lenght of the name entry.


greets,
Martin
 
M

Martin Pohlack

Martin Dickopp wrote:
If your only concern is wasted space, I wouldn't worry about it. An
instance of a structure which is not used except that its members are
operands to the `sizeof' operator is likely to be optimized away by
the compiler.

Of course, this whole discussion is just about a potential waste of 4
bytes on the stack (on x86) for a pointer to a struct. But I,
_perfectionistic_ as I am, just wanted to know whether there is a way of
syntactically correct expressing the size of struct members without an
instance or pointer like with sizeof(int). That is all.

greets,
Martin
 
M

Martin Dickopp

Jack Klein said:
Nope, it's not, honest. It's been beaten to death a few times in
comp.std.c. Try a google search there.

I see I have been wrong.

Martin
 
M

Martin Dickopp

Martin Pohlack said:
I'm actually implementing some kind of fileserver, using a posix like
interface (open, close, read, write, ...). For directory handling I had a
look at the 'getdents()' systemcall of linux, which reads as follows:

int getdents(unsigned int fd, struct dirent *dirp, unsigned int count);

<OT>
You are more or less reimplementing the POSIX functions `opendir',
`readdir', and `closedir'. You could have a look at how they are
implemented in the GNU C Library.
</OT>

Martin
 
M

Martin Pohlack

<OT>
You are more or less reimplementing the POSIX functions `opendir',
`readdir', and `closedir'. You could have a look at how they are
implemented in the GNU C Library.
</OT>


No, not really. I'm impl. the "backend" for those. I port the dietlibc
based on those backends to our system (DROPS
http://os.inf.tu-dresden.de/drops).

But thanks for the suggestion!

Martin
 
I

Irrwahn Grausewitz

Jack Klein said:
Nope, it's not, honest. It's been beaten to death a few times in
comp.std.c. Try a google search there.

In another branch of this thread you explained (and enlightened me):

JK> [...] In fact it is perfectly well defined, because the
JK> sizeof operator is evaluated at compile time based on the type
JK> of the operand and does not evaluate at run time at all. [...]

So, this should be perfectly legal even for several "levels of
referencing" between structs, right?

E.g., consider the following code snippet:

struct foo {
int boogle;
}

struct bar {
struct foo *p_foo;
};

struct baz {
struct bar *p_bar;
};

size_t boogle_size = sizeof ((struct baz *) NULL)->p_bar->p_foo->boogle;

Is this legal use of sizeof?

Thanks in advance,

Irrwahn
 
K

Keith Thompson

Martin Pohlack said:
I have a funtion which shall compute the amount for a later malloc. In
this function I need the sizes of some struct members without having
an instance or pointer of the struct.

As "sizeof(int)" is legal I assumed "sizeof(struct x.y)" to be legal
too. But is is not: [snip]
#include <dirent.h>

int dir_dirent_size(dir_t * dirp)
{
int len;
struct dirent * temp;

// syntax error
len = sizeof(temp.d_ino) +
sizeof(temp.d_off) +
sizeof(temp.d_reclen) +
strlen(dirp->name) + 1;

return len;
}

What are you going to store in the malloc'ed memory? If you're going
to store the d_ino, d_off, and d_reclen values individually at
specified byte offsets, adding their sizes probably makes sense (be
sure to use memcopy() et al to access the values, since they may not
be aligned correctly). If you're going to store an object of type
"struct dirent", you could be in trouble, since you're ignoring any
possible padding between the members.
 

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,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top