Portability regarding sizeof() function

B

Behzad

Hi all,

I am totally new to the field of portability. One point at the time of
coding i thought would be problem in portability was the use of sizeof
().Now I have read some pages in the net about issues on the
portability. After reading those pages and be assured that sizeof()
can be dangerous,now i am preparing a solution. I was wondering if
there are some best practices regarding sizeof() and Portability at
all.

Can anybody help me to get some solutions and practices?

Thanks in advance,
Behzad
 
B

Ben Pfaff

Behzad said:
I am totally new to the field of portability. One point at the time of
coding i thought would be problem in portability was the use of sizeof
().Now I have read some pages in the net about issues on the
portability. After reading those pages and be assured that sizeof()
can be dangerous,now i am preparing a solution. I was wondering if
there are some best practices regarding sizeof() and Portability at
all.

In what way can sizeof be dangerous? What pages make these
claims?
 
K

Keith Thompson

Behzad said:
I am totally new to the field of portability. One point at the time of
coding i thought would be problem in portability was the use of sizeof
().Now I have read some pages in the net about issues on the
portability. After reading those pages and be assured that sizeof()
can be dangerous,now i am preparing a solution. I was wondering if
there are some best practices regarding sizeof() and Portability at
all.

Can anybody help me to get some solutions and practices?

First off, sizeof is an operator, not a function.

I'm not sure what you mean when you say that "sizeof() can be
dangerous". For any type bigger than char, applying sizeof to that
type will give you an implementation-defined result. It's guaranteed
to be the actual size in bytes of that type, but that actual size can
vary from one implementation to another. For example, sizeof(int)
might be 2 on one system, 4 on another, or even 1 (if CHAR_BIT >= 16,
which is common for DSPs).

There is nothing inherently dangerous about the sizeof operator. It
can be used in dangerous ways, but so can any feature of any language.

Can you be more specific about your concerns?
 
J

James Kuyper

Behzad said:
Hi all,

I am totally new to the field of portability. One point at the time of
coding i thought would be problem in portability was the use of sizeof
().Now I have read some pages in the net about issues on the
portability. After reading those pages and be assured that sizeof()
can be dangerous,now i am preparing a solution. I was wondering if
there are some best practices regarding sizeof() and Portability at
all.

Can anybody help me to get some solutions and practices?

Appropriate use of sizeof is essential to writing portable code. Example:

struct tm *t = malloc(sizeof *t);

Would you care to suggest a more portable way of doing that which
doesn't involve use of the sizeof operator?

Inappropriate use of sizeof can be dangerous, but then so can
inappropriate use of just about any other feature of C.
 
C

CBFalconer

James said:
.... snip ...

Appropriate use of sizeof is essential to writing portable code.
Example:
struct tm *t = malloc(sizeof *t);

Would you care to suggest a more portable way of doing that which
doesn't involve use of the sizeof operator?

Inappropriate use of sizeof can be dangerous, but then so can
inappropriate use of just about any other feature of C.

Nit. I don't think that works. When sizeof is executed t has not
yet been defined. I think it awaits the final semi.
 
B

Ben Bacarisse

CBFalconer said:
Nit. I don't think that works. When sizeof is executed t has not
yet been defined. I think it awaits the final semi.

That is not so. I can't find the place where the standard states that
an identifier is defined from the declarator onwards, but that has
always been my understanding. I.e. even

char c, *cp = &c;

is valid.

If you are right an I am wrong, I am in good company. gcc (and every
other compiler I remember using) prints the size of one int here, not
two:

#include <stdio.h>

int i[2];

int main(void)
{
int i = sizeof i;
printf("%d\n", i);
return 0;
}

[The reason I am so sure about what compilers used to do is not a
stellar one; I used to like to write code like this:

char buffer[SOME_SIZE], *bp = buffer;

when I needed some space and a pointer into it. I would never do that
now, of course!]
 
B

Behzad

Sorry for late response.

Maybe instead of using 'dangerous', i should use another word!

Anyway, when Let's explain more with an example:

/*-------------------------------------------------------*/
void somefunc(u8* resp,u8* buff)
{
u8* ptr = buff;

ptr = *(int*)&resp[4];
ptr += sizeof(float);

ptr = *(int*)&resp[12];
ptr += sizeof(int);

ptr = *(int*)&resp[16];
ptr += sizeof(short);

}
/*-------------------------------------------------------*/

The above example should be able to run on x86 or ARM machine.Each
machine could have Linux or Windows(XP,CE,etc...) installed on.
so my concerns are the above codes that are ( in my opinion) highly
dependent on the machine and OS implementations.
Do also include Big-endian and Little-endian issues.

Behzad
 
K

Keith Thompson

CBFalconer said:
Nit. I don't think that works. When sizeof is executed t has not
yet been defined. I think it awaits the final semi.

Yes, it does work (though it took me a while to find the section in
the standard that proves it).

The object exists even before the declaration is reached. C99 6.2.4p4-5:

An object whose identifier is declared with no linkage and without
the storage-class specifier static has _automatic storage
duration_.

For such an object that does not have a variable length array
type, its lifetime extends from entry into the block with which it
is associated until execution of that block ends in any way.

But the real question is the scope. C99 6.2.1p7 says:

Structure, union, and enumeration tags have scope that begins just
after the appearance of the tag in a type specifier that declares
the tag. Each enumeration constant has scope that begins just
after the appearance of its defining enumerator in an enumerator
list. Any other identifier has scope that begins just after the
completion of its declarator.

In the declaration above:

struct tm *t = malloc(sizeof *t);

the declarator is ``*t'', the scope of t begins before the "=", and
the initializer is valid.

Incidentally, the fact that the lifetime of an automatic object starts
on entry to the block, before the declaration itself is reached, has
some interesting, though probably not very useful, consequences.

#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i <= 1; i ++) {
int *foo_addr;
if (i == 1) {
printf("foo isn't visible yet, but its value is %d\n", *foo_addr);
}
int foo = 42;
if (i == 0) {
foo_addr = &foo;
}
}
return 0;
}

The output is:

foo isn't visible yet, but its value is 42
 
B

Ben Pfaff

Keith Thompson said:
Incidentally, the fact that the lifetime of an automatic object starts
on entry to the block, before the declaration itself is reached, has
some interesting, though probably not very useful, consequences.

#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i <= 1; i ++) {
int *foo_addr;
if (i == 1) {
printf("foo isn't visible yet, but its value is %d\n", *foo_addr);
}
int foo = 42;
if (i == 0) {
foo_addr = &foo;
}
}
return 0;
}

I think you're missing an important fact here. The block that
starts on the line of the "for" loop is exited just before i++ is
evaluated, and then it is re-entered in the second iteration of
the loop. Therefore, the value of foo_addr is indeterminate when
*foo_addr is evaluated during the second iteration, and therefore
this code yields undefined behavior.
 
K

Keith Thompson

Ben Pfaff said:
I think you're missing an important fact here. The block that
starts on the line of the "for" loop is exited just before i++ is
evaluated, and then it is re-entered in the second iteration of
the loop. Therefore, the value of foo_addr is indeterminate when
*foo_addr is evaluated during the second iteration, and therefore
this code yields undefined behavior.

You're right, good catch.

(It happened to "work" because both instances of foo, and of foo_addr,
happen to have the "same" address. I put "same" in quotes because the
addresses of the two instances can't be compared without invoking UB.)

I could construct an example of the same thing that actually works
using a goto, but I don't think I'll bother.
 
B

BartC

Anyway, when Let's explain more with an example:
void somefunc(u8* resp,u8* buff)
{
u8* ptr = buff;

ptr = *(int*)&resp[4];
ptr += sizeof(float);

ptr = *(int*)&resp[12];
ptr += sizeof(int);

ptr = *(int*)&resp[16];
ptr += sizeof(short);

}
/*-------------------------------------------------------*/

Perhaps the examples can make more sense like this:

ptr = *(float*)&resp[4];
ptr += sizeof(float);

ptr = *(int*)&resp[12];
ptr += sizeof(int);

ptr = *(short*)&resp[16];
ptr += sizeof(short);

machine could have Linux or Windows(XP,CE,etc...) installed on.
so my concerns are the above codes that are ( in my opinion) highly
dependent on the machine and OS implementations.
Do also include Big-endian and Little-endian issues.

Depends on where the resp[] array comes from. If from an outside source such
as a file, then yes there could be all sorts of issues.

If the resp is external and it's spec details exactly the type and width of
the values it contains, then perhaps you're right and using sizeof(short)
could be 'dangerous', if the machine's short is a different size from that
specified for resp[].
 
B

Behzad

If the resp is external and it's spec details exactly the type and width of
the values it contains, then perhaps you're right and using sizeof(short)
could be 'dangerous',

Thanks God someone got my point.
I know this may cause a problem. What are your preferred solutions or
practices?
 
J

James Kuyper

Behzad said:
Thanks God someone got my point.
I know this may cause a problem. What are your preferred solutions or
practices?

It might help, perhaps, to provide a example showing your point which
includes a function that does something not equivalent to {return;}, and
which is placed in a context sufficiently well explained that we can
figure out why it is a problem.
 
J

James Kuyper

Behzad said:
Sorry for late response.

Maybe instead of using 'dangerous', i should use another word!

Anyway, when Let's explain more with an example:

/*-------------------------------------------------------*/
void somefunc(u8* resp,u8* buff)
{
u8* ptr = buff;

ptr = *(int*)&resp[4];
ptr += sizeof(float);

ptr = *(int*)&resp[12];
ptr += sizeof(int);

ptr = *(int*)&resp[16];
ptr += sizeof(short);

buff is completely unused. ptr is set six times by that code, without
having ever been used. somefunc() could be replaced by a nop. Whatever
point you are trying to make has pretty much gotten lost by presenting a
bad example
}
/*-------------------------------------------------------*/

The above example should be able to run on x86 or ARM machine.Each
machine could have Linux or Windows(XP,CE,etc...) installed on.
so my concerns are the above codes that are ( in my opinion) highly
dependent on the machine and OS implementations.

Code like "p += sizeof(int);" is indeed highly implementation-dependent.
However, assuming that it is used in the right way, that very same
dependency is precisely what enables the program as a whole to be
portable, because it provides a way to compensate for the corresponding
implementation-dependence of the size of an int.
Do also include Big-endian and Little-endian issues.

Endianess is certainly an issue that can complicate the writing of
portable code, but it's not clear what you want to say about it.
 
F

Flash Gordon

Behzad said:
Thanks God someone got my point.
I know this may cause a problem. What are your preferred solutions or
practices?

If you are reading data where the specification says you have a number
made up of two bytes in big-endian format then that is what you read.
If, on the other hand, you want to know the size of a type or expression
within the program you use sizeof. Two different problems with two
different solutions.
 
B

Ben Bacarisse

Keith Thompson said:
But the real question is the scope. C99 6.2.1p7 says:

Structure, union, and enumeration tags have scope that begins just
after the appearance of the tag in a type specifier that declares
the tag. Each enumeration constant has scope that begins just
after the appearance of its defining enumerator in an enumerator
list. Any other identifier has scope that begins just after the
completion of its declarator.

Thank you. You have no idea how hard I tried to find that wording!
 
L

luserXtrog

If Chuck Falconer is right? Haha, good one. Not only is he wrong,
but he knows he's wrong. After all that's been seen on this
newsgroup, the only people not attributing disruptive intent to
Chuck Falconer are suckers, plain and simple.  

And what intent does this post serve?
 
B

Ben Bacarisse

Richard Heathfield said:
CBFalconer said:


How do you reconcile your opinion with what the Standard says in
3.1.2.1 of C89 (or 6.2.1(4) of C99), given that the Standard's take
on the matter appears to be diametrically opposite to yours?

The last sentence of 6.2.1(7) seems to be the operative one.

It is a shame that the common case is documented as the exception at
the end of a paragraph. I'd prefer a new paragraph for it, but that
would require more words (but I say that only because I failed
to notice it on more than one reading).
 
B

BartC

Richard Heathfield said:
BartC said:

Perhaps the examples can make more sense like this:

ptr = *(float*)&resp[4];
ptr += sizeof(float);

ptr = *(int*)&resp[12];
ptr += sizeof(int);

ptr = *(short*)&resp[16];
ptr += sizeof(short);

No, not really. It's still equivalent to a no-op once the function
returns.

I didn't pay attention to the left-hand-sides, because I didn't think the
function was supposed to do anything useful, other than provide a (not very
good) example context for the use of sizeof.

Looking at it more carefully, perhaps there was a point to it (copy some
fields of resp to buff), although some pointer dereferences and casts are
missing on the ptr= lines. Whether the use of sizeof is still questionable
in this case depends on further info.
 

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top