K
Keith Thompson
Rod Pemberton said:[...]Rod Pemberton a écrit :
Do the typical macro definitions of offsetof() (e.g., C Rationale or
X11?) work correctly with LCC-Win32? That strongly suggests to me
they don't.
If they do, then there is no need for sizeof(). Only slight
adjustment of an existing struct is required. Structs can also be
constructed to determine the size of other types. If one is
paranoid about incorrect value due to alignment issues, then one
could do multiple checks.
I think I see what you're trying to say.
The offsetof() macro itself is of no help as a sizeof replacement, but
the typical definition of the offsetof() macro can be adapted for that
purpose by means of some ugly pointer arithmetic trickery. Here's a
small program that demonstrates the method:
#include <stdio.h>
#include <time.h>
#define SIZE_OF_TYPE(type) \
((size_t)((char*)((type(*)[1])0 + 1) - \
(char*)(type(*)[1])0))
#define SIZE_OF_OBJECT(obj) \
((size_t)((char*)(&(obj) + 1) - (char*)&(obj)))
int main(void)
{
int int_obj;
double double_obj;
struct tm tm_obj;
int n = 42;
float vla[n];
printf("SIZE_OF_TYPE(int) = %lu\n",
(unsigned long)SIZE_OF_TYPE(int));
printf("SIZE_OF_TYPE(double) = %lu\n",
(unsigned long)SIZE_OF_TYPE(double));
printf("SIZE_OF_TYPE(struct tm) = %lu\n",
(unsigned long)SIZE_OF_TYPE(struct tm));
putchar('\n');
printf("sizeof(int(*)[4]) = %lu\n",
(unsigned long)sizeof(int(*)[4]));
putchar('\n');
printf("SIZE_OF_OBJECT(int_obj) = %lu\n",
(unsigned long)SIZE_OF_OBJECT(int_obj));
printf("SIZE_OF_OBJECT(double_obj) = %lu\n",
(unsigned long)SIZE_OF_OBJECT(double_obj));
printf("SIZE_OF_OBJECT(tm_obj) = %lu\n",
(unsigned long)SIZE_OF_OBJECT(tm_obj));
printf("SIZE_OF_OBJECT(vla) = %lu\n",
(unsigned long)SIZE_OF_OBJECT(vla));
return 0;
}
Of course these macros have some significant drawbacks:
Separate macros are required for ``sizeof (type)'' and ``sizeof
object''.
SIZE_OF_OBJECT() applies only to lvalues.
SIZE_OF_OBJECT evaluates its argument twice (compared to the built-in
"sizeof" operator, which doesn't evaluates its argument at all
unless it's a VLA).
SIZE_OF_OBJECT cannot be applied to certain complex type names,
such as int(*)[4]. This can be worked around by adding a typedef.
Both macros invoke undefined behavior when expanded, just
as an expansion of the usual definition of offsetof() does.
Like offsetof(), they're likely to work on most implementations.
They yield an intermediate result of type ptrdiff_t, which is then
converted to size_t. This may cause problems for very large types
and objects on some systems (though the overflow on the subtraction
and the overflow on the conversion may well cancel each other out,
yielding the correct answer anyway).
Finally, they're ugly.
(It's likely I've missed some cases.)
So yes, strictly speaking the sizeof operator is unnecessary.
If I had to work in a crippled language that's like C but with the
sizeof operator removed, I could work around the problem in most
cases by defining and using these macros.
Is that really what you had in mind? If so, why waste your time?
sizeof exists for a reason. Just use it.