By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,192 Members | 858 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,192 IT Pros & Developers. It's quick & easy.

Implementing the sizeof operator

P: n/a
Hi,

Somebody recently asked me to implement the sizeof operator, i.e. to
write a function that accepts a parameter of any type, and without
using the sizeof operator, should be able to return the size occupied
by that datatype in memory in bytes. Thanks :)

Abhishek Srivastava

Jul 5 '06 #1
Share this Question
Share on Google+
32 Replies


P: n/a
* Abhishek Srivastava:
>
Somebody recently asked me to implement the sizeof operator, i.e. to
write a function that accepts a parameter of any type, and without
using the sizeof operator, should be able to return the size occupied
by that datatype in memory in bytes. Thanks :)
This sounds like HOMEWORK.

One must hope that nobody provides source code for you (although they
invariably do, to show off their ability to code trivial things).

Hint: array.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 5 '06 #2

P: n/a
Abhishek Srivastava wrote:
Hi,

Somebody recently asked me to implement the sizeof operator, i.e. to
write a function that accepts a parameter of any type, and without
using the sizeof operator, should be able to return the size occupied
by that datatype in memory in bytes. Thanks :)
Note that the difference in address between two adjacent elements of an
array is equal to the size of an element.

Tom
Jul 5 '06 #3

P: n/a
Hi Alf P. Steinbach :)

This is not homework. Just wanted to know because I couldn't think of
the solution. Hmmmm.... your hint is to use an array, still pondering
over that. Thanks anyway.

Alf P. Steinbach wrote:
* Abhishek Srivastava:

Somebody recently asked me to implement the sizeof operator, i.e. to
write a function that accepts a parameter of any type, and without
using the sizeof operator, should be able to return the size occupied
by that datatype in memory in bytes. Thanks :)

This sounds like HOMEWORK.

One must hope that nobody provides source code for you (although they
invariably do, to show off their ability to code trivial things).

Hint: array.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 5 '06 #4

P: n/a
Abhishek Srivastava posted:
Hi,

Somebody recently asked me to implement the sizeof operator, i.e. to
write a function that accepts a parameter of any type, and without
using the sizeof operator, should be able to return the size occupied
by that datatype in memory in bytes. Thanks :)

Abhishek Srivastava

#include <cstddef>

template<class T>
struct SizeOfHelper {

T array[2];

};

#define SizeOf(T) offsetof(SizeOfHelper<T>, array[1])
I don't mind doing this homework question for people, because it's
utterly pointless.
--

Frederick Gotham
Jul 5 '06 #5

P: n/a
Frederick Gotham wrote:
Abhishek Srivastava posted:

>>Hi,

Somebody recently asked me to implement the sizeof operator, i.e. to
write a function that accepts a parameter of any type, and without
using the sizeof operator, should be able to return the size occupied
by that datatype in memory in bytes. Thanks :)

Abhishek Srivastava

#include <cstddef>

template<class T>
struct SizeOfHelper {

T array[2];

};

#define SizeOf(T) offsetof(SizeOfHelper<T>, array[1])
I don't mind doing this homework question for people, because it's
utterly pointless.
Your implementation is incorrect in any case. offsetof is only defined
for POD types.

Tom
Jul 5 '06 #6

P: n/a
Abhishek Srivastava wrote:
Hi,

Somebody recently asked me to implement the sizeof operator, i.e. to
write a function that accepts a parameter of any type, and without
using the sizeof operator, should be able to return the size occupied
by that datatype in memory in bytes.
Interesting story.
Thanks :)
What for?

Jul 5 '06 #7

P: n/a
Tom Widmer posted:

Your implementation is incorrect in any case. offsetof is only defined
for POD types.

Yes, and thankfully, my type is a POD.
--

Frederick Gotham
Jul 5 '06 #8

P: n/a
Frederick Gotham wrote:
Tom Widmer posted:

>Your implementation is incorrect in any case. offsetof is only defined
for POD types.


Yes, and thankfully, my type is a POD.
There's a second problem too; offsetof is defined for
member-designators, and "array[1]" isn't a member-designator.

Tom
Jul 5 '06 #9

P: n/a
Frederick Gotham wrote:
Tom Widmer posted:

>Your implementation is incorrect in any case. offsetof is only defined
for POD types.


Yes, and thankfully, my type is a POD.
Do you mean SizeOfHelper<Tis a POD type? It is a POD type if and
only if T is a POD type.

Tom

Jul 5 '06 #10

P: n/a
Tom Widmer posted:
Frederick Gotham wrote:
>Tom Widmer posted:

>>Your implementation is incorrect in any case. offsetof is only defined
for POD types.


Yes, and thankfully, my type is a POD.

Do you mean SizeOfHelper<Tis a POD type? It is a POD type if and
only if T is a POD type.

Oh I see where you're coming from. Alas, my code is flawed.

--

Frederick Gotham
Jul 5 '06 #11

P: n/a
Abhishek Srivastava wrote:
Hi Alf P. Steinbach :)

This is not homework. Just wanted to know because I couldn't think of
the solution. Hmmmm.... your hint is to use an array, still pondering
over that. Thanks anyway.
Please don't top-post. Your replies belong following or interspersed
with properly trimmed quotes. See the newsgroup FAQ:

<http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.4>


Brian
Jul 5 '06 #12

P: n/a
Tom Widmer wrote:
Frederick Gotham wrote:
Tom Widmer posted:

Your implementation is incorrect in any case. offsetof is only defined
for POD types.

Yes, and thankfully, my type is a POD.

Do you mean SizeOfHelper<Tis a POD type? It is a POD type if and
only if T is a POD type.

Tom
Hi,

Thanks all :) Once again I reiterate, it was not a homework question.
It was actually an interview question. Atleast now I've got the answer
if not the job ... ;)

Thanks again,
Abhishek Srivastava

Jul 6 '06 #13

P: n/a
May I conclude that there was no real solution mentioned here so far?

offsetof:

only for member designators, POD
array:
what about alignment?
I think the right answer is that there is no universal replacement for
sizeof

Am I missing something?

Cheers,
Marc

Jul 6 '06 #14

P: n/a
m_*********@hotmail.com posted:

array:
what about alignment?

(1) The first member of a POD has the same address as the POD itself.

(2) There's no padding between array elements.
So alignment isn't a problem.

If you're not allowed to create a temporary, then I think the following
is the closest thing you could have to "sizeof" for a type:

#define sizeof(T) \
(char const *)( ((T) const *)32 + 1 ) \
-(char const *)( ((T) const *)32 ) \
If, however, you want the size of an object, or perhaps the size of a
type (but you can use a temporary), then it's trivial:
#include <iostream>
#include <cstddef>

template<class T>
std::size_t SizeOf( T const &obj = T() )
{
return (char const *)(&obj + 1) - (char const *)(&obj);
}

int main()
{
unsigned i;

std::cout << SizeOf(i);

std::cout << SizeOf<unsigned>();
}
--

Frederick Gotham
Jul 6 '06 #15

P: n/a
(1) The first member of a POD has the same address as the POD itself.

??? A POD has no members...
But I think I understand what you mean.
(2) There's no padding between array elements.
Is this really true? (Written in the standard?)
Hard to believe. If it is so, padding at all would be pretty useless.

Consider:

struct A { long int a; char b; long int c};

A arr[4];

(on a lets say 32bit machine with 32 bit long integer).
This way each element of arr would be aligned to another byte address.
Marc

Jul 6 '06 #16

P: n/a
m_*********@hotmail.com posted:
> (1) The first member of a POD has the same address as the POD
itself.

??? A POD has no members...
But I think I understand what you mean.

struct I_am_a_POD {

char c;
int i;
void *p;
};

> (2) There's no padding between array elements.

Is this really true? (Written in the standard?)
Hard to believe.

How else could we use pointers to iterate through an array?
#include <cassert>
#include <cstddef>

template<class T>
void ZeroArray( T *p, std::size_t const len )
{
assert(len >= 1);

T const * const p_over = p + len;

do
{
*p++ = T();
} while ( p != p_over );
}

int main()
{
double array[16] = {1,2,3,4,5,6,7,8,
9,10,11,12,13,14,15,16};

ZeroArray( array, sizeof(array) / sizeof(*array) );
}
Consider:

struct A { long int a; char b; long int c};

A arr[4];

(on a lets say 32bit machine with 32 bit long integer).
This way each element of arr would be aligned to another byte address.

Within an object of type "A", there may be padding between the members.

Within an array of objects of type "A", there may NOT be padding between
the elements.
--

Frederick Gotham
Jul 6 '06 #17

P: n/a
* Frederick Gotham:
>
If you're not allowed to create a temporary, then I think the following
is the closest thing you could have to "sizeof" for a type:

#define sizeof(T) \
(char const *)( ((T) const *)32 + 1 ) \
-(char const *)( ((T) const *)32 ) \
Prefer a template function to a macro. One problem with macros is that
they can easily conflict with language and standard library names. The
above one does, and that's a practical problem, not just a formal one.

If, however, you want the size of an object, or perhaps the size of a
type (but you can use a temporary), then it's trivial:
#include <iostream>
#include <cstddef>

template<class T>
std::size_t SizeOf( T const &obj = T() )
{
return (char const *)(&obj + 1) - (char const *)(&obj);
}
This isn't as trivial as you think.

1) The type may not have an accessible default constructor, which means
you cannot use T().

2) The type may not have an accessible copy constructor, which means you
cannot portably pass the argument by reference to const (yeah, in case
you wonder, currently having an accessible copy constructor is a
requirement for passing by reference to const, although that's so
infinitely silly that the requirement will be removed in C++0x).

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 6 '06 #18

P: n/a
m_*********@hotmail.com wrote:
(1) The first member of a POD has the same address as the POD itself.

??? A POD has no members...
Wrong. struct X { int a,b } is a POD.
But I think I understand what you mean.
(2) There's no padding between array elements.

Is this really true? (Written in the standard?)
Hard to believe. If it is so, padding at all would be pretty useless.
It's useful, when you're mixing members with different alignment
requirements inside a struct. The fact that it's true isn't literally
in the
standard, but the standard requires that incrementing any T* by 1
gives an address that's sizeof(T) larger. I.e. for any T* ptr that
points to
a T (non-null), (char*)(ptr)+sizeof(T) = (char*)(ptr+1)

And thus, for any T* pt, sizeof(T)=(char*)(ptr+1)-(char*)(ptr) which
is the answer that the TS needed.

Arrays are not required, as any element is similar to an array of
length 1.

HTH,
Michiel Salters

Jul 6 '06 #19

P: n/a
Alf P. Steinbach posted:

2) The type may not have an accessible copy constructor, which means
you
cannot portably pass the argument by reference to const (yeah, in case
you wonder, currently having an accessible copy constructor is a
requirement for passing by reference to const, although that's so
infinitely silly that the requirement will be removed in C++0x).

I think that applies only if the argument being passed is an R-value:

class Arb {
private:

Arb( Arb const & );
Arb &operator=( Arb const & );

public:

Arb() {}
};
void Func(Arb const &) {}

int main()
{
Arb obj;

Func(obj); /* No problem */

Func( Arb() ); /* Compiler ERROR */
}
And that makes perfect sense to me if you consider the rules for binding
a const reference to an R-value:

"...a temporary of type 'cv1 T1' is created and initialized
from the initializer expression using the rules for a
non-reference copy initialization (8.5). The reference
is then bound to the temporary."
--

Frederick Gotham
Jul 6 '06 #20

P: n/a
* Frederick Gotham:
Alf P. Steinbach posted:
>2) The type may not have an accessible copy constructor, which means
you
>cannot portably pass the argument by reference to const (yeah, in case
you wonder, currently having an accessible copy constructor is a
requirement for passing by reference to const, although that's so
infinitely silly that the requirement will be removed in C++0x).


I think that applies only if the argument being passed is an R-value:
Yes, and that's what you have with the "=" default argument.

The problem stems from trying to pack too much into one function.

Make it two functions: one that has no argument, and one that has one
argument (no default value).

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 6 '06 #21

P: n/a
"Alf P. Steinbach" <al***@start.nowrote in message
news:4h*************@individual.net...
>* Frederick Gotham:
>>
If you're not allowed to create a temporary, then I think the following
is the closest thing you could have to "sizeof" for a type:

#define sizeof(T) \
(char const *)( ((T) const *)32 + 1 ) \
-(char const *)( ((T) const *)32 ) \

Prefer a template function to a macro. One problem with macros is that
they can easily conflict with language and standard library names. The
above one does, and that's a practical problem, not just a formal one.
Is there any way to preserve the same syntax with a template function
though? With the macro version you can use a type name as the parameter,
i.e. sizeof(int) or whatever (ignoring the fact that sizeof already exists
for the moment), but I can't think how you'd do that with a template
function. Any thoughts?

Also, why are we casting 32 in the above? I can see how it works, but why
the seemingly arbitrary magic number? Am I missing something obvious or
would any number work there? (Is alignment an issue here? Just a thought,
may be nonsense! (It is quite late...))

Cheers :)
Stu
>If, however, you want the size of an object, or perhaps the size of a
type (but you can use a temporary), then it's trivial:
#include <iostream>
#include <cstddef>

template<class T>
std::size_t SizeOf( T const &obj = T() )
{
return (char const *)(&obj + 1) - (char const *)(&obj);
}

This isn't as trivial as you think.

1) The type may not have an accessible default constructor, which means
you cannot use T().

2) The type may not have an accessible copy constructor, which means you
cannot portably pass the argument by reference to const (yeah, in case you
wonder, currently having an accessible copy constructor is a requirement
for passing by reference to const, although that's so infinitely silly
that the requirement will be removed in C++0x).

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Jul 7 '06 #22

P: n/a
Stuart Golodetz posted:

Also, why are we casting 32 in the above? I can see how it works, but
why the seemingly arbitrary magic number? Am I missing something obvious
or would any number work there? (Is alignment an issue here? Just a
thought, may be nonsense! (It is quite late...))

I had to hazard a guess as to what would be a valid address on the majority
of platforms. A power of 2 sounded nice.

--

Frederick Gotham
Jul 7 '06 #23

P: n/a

Stuart Golodetz wrote:
"Alf P. Steinbach" <al***@start.nowrote in message
news:4h*************@individual.net...
* Frederick Gotham:
>
If you're not allowed to create a temporary, then I think the following
is the closest thing you could have to "sizeof" for a type:

#define sizeof(T) \
(char const *)( ((T) const *)32 + 1 ) \
-(char const *)( ((T) const *)32 ) \
Prefer a template function to a macro. One problem with macros is that
they can easily conflict with language and standard library names. The
above one does, and that's a practical problem, not just a formal one.

Is there any way to preserve the same syntax with a template function
though? With the macro version you can use a type name as the parameter,
i.e. sizeof(int) or whatever (ignoring the fact that sizeof already exists
for the moment), but I can't think how you'd do that with a template
function. Any thoughts?
size_of<T>::value

would be the 'equivalent' template syntax to the macro.
I think the implementation would be:

template <typename T>
struct size_of
{
static const std::size_t value = (std::size_t)(char *)( (T *)0 + 1
); //orsomethinglikethat
};
>
Also, why are we casting 32 in the above? I can see how it works, but why
the seemingly arbitrary magic number? Am I missing something obvious or
would any number work there? (Is alignment an issue here? Just a thought,
may be nonsense! (It is quite late...))
Some compilers (gcc), on highest warning levels, complain when you cast
0 to a pointer, using 32 instead of 0 makes the macro more complicated,
but removes the warning.

Cheers :)
Stu
- Tony

Jul 7 '06 #24

P: n/a
A simple macro that computes the size of type:

#define SIZE(type) ((type*)0 +1)

i have verified its credibility for built in types, dont know about
compound types

regards
Sam

go**********@gmail.com wrote:
Stuart Golodetz wrote:
"Alf P. Steinbach" <al***@start.nowrote in message
news:4h*************@individual.net...
>* Frederick Gotham:
>>
>If you're not allowed to create a temporary, then I think the following
>is the closest thing you could have to "sizeof" for a type:
>>
> #define sizeof(T) \
> (char const *)( ((T) const *)32 + 1 ) \
> -(char const *)( ((T) const *)32 ) \
>
Prefer a template function to a macro. One problem with macros is that
they can easily conflict with language and standard library names. The
above one does, and that's a practical problem, not just a formal one.
Is there any way to preserve the same syntax with a template function
though? With the macro version you can use a type name as the parameter,
i.e. sizeof(int) or whatever (ignoring the fact that sizeof already exists
for the moment), but I can't think how you'd do that with a template
function. Any thoughts?

size_of<T>::value

would be the 'equivalent' template syntax to the macro.
I think the implementation would be:

template <typename T>
struct size_of
{
static const std::size_t value = (std::size_t)(char *)( (T *)0 + 1
); //orsomethinglikethat
};

Also, why are we casting 32 in the above? I can see how it works, but why
the seemingly arbitrary magic number? Am I missing something obvious or
would any number work there? (Is alignment an issue here? Just a thought,
may be nonsense! (It is quite late...))

Some compilers (gcc), on highest warning levels, complain when you cast
0 to a pointer, using 32 instead of 0 makes the macro more complicated,
but removes the warning.

Cheers :)
Stu

- Tony
Jul 7 '06 #25

P: n/a
Frederick Gotham wrote:
m_*********@hotmail.com posted:

>array:
what about alignment?


(1) The first member of a POD has the same address as the POD itself.

(2) There's no padding between array elements.
So alignment isn't a problem.

If you're not allowed to create a temporary, then I think the following
is the closest thing you could have to "sizeof" for a type:

#define sizeof(T) \
(char const *)( ((T) const *)32 + 1 ) \
-(char const *)( ((T) const *)32 ) \
Of course, that isn't legal because you're performing pointer arithmetic
on an invalid pointer value. Also, the result isn't an integral constant
expression, so can't be used as, e.g., an array bound.
If, however, you want the size of an object, or perhaps the size of a
type (but you can use a temporary), then it's trivial:
#include <iostream>
#include <cstddef>

template<class T>
std::size_t SizeOf( T const &obj = T() )
{
return (char const *)(&obj + 1) - (char const *)(&obj);
}

int main()
{
unsigned i;

std::cout << SizeOf(i);

std::cout << SizeOf<unsigned>();
}
Doesn't work for:
1. Non-default constructibles
2. Abstract classes
3. Arrays
4. Other non-copyables
5. References
6. Local types

Here's my version that fixes 1-5, but has other problems (only works up
to a certain type size).

#include <iostream>
#include <cstddef>

std::size_t const biggerThanAnyType = 10000000;
char largeStorage[biggerThanAnyType];
void* const largeStorageP = largeStorage;

template <class T>
struct SizeOf
{
static std::size_t value()
{
return f();
}
private:
static std::size_t f( T const *obj = static_cast<T const*>(largeStorageP))
{
void const* p1 = obj;
void const* p2 = obj + 1;
return static_cast<char const*>(p2) - static_cast<char const*>(p1);
}
};

template <class T, std::size_t N>
struct SizeOf<T[N]>
{
static std::size_t value()
{
return N * SizeOf<T>::value();
}
};

template <class T>
struct SizeOf<T&>
{
static std::size_t value()
{
return SizeOf<T>::value();
}
};

struct Abstract
{
virtual void f() = 0;
};

#define SizeOf(T) (SizeOf<T>::value())

int main()
{
std::cout << SizeOf(int) << '\n';
typedef int array[10][20];
std::cout << SizeOf(array) << '\n';
std::cout << SizeOf(Abstract) << '\n';
std::cout << SizeOf(double&) << '\n';
}

I think it's standards conforming, though I'm happy for someone to pick
it apart.

Tom
Jul 7 '06 #26

P: n/a
posted:
A simple macro that computes the size of type:

#define SIZE(type) ((type*)0 +1)

i have verified its credibility for built in types, dont know about
compound types

On your own system, perhaps.

It's undefined behaviour as far as the Standard is concerned, because there
is no gurantee that you can increment a null pointer and be left with a valid
address.

For the same reason, "offsetof" is implemented differently on different
platforms.
--

Frederick Gotham
Jul 7 '06 #27

P: n/a
Sa*******@gmail.com wrote:
A simple macro that computes the size of type:
Please don't top-post. Your replies belong following or interspersed
with properly trimmed quotes. See the newsgroup FAQ entry:

<http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.4>


Brian
Jul 7 '06 #28

P: n/a

Frederick Gotham wrote:
posted:
A simple macro that computes the size of type:

#define SIZE(type) ((type*)0 +1)

i have verified its credibility for built in types, dont know about
compound types


On your own system, perhaps.

It's undefined behaviour as far as the Standard is concerned, because there
is no gurantee that you can increment a null pointer and be left with a valid
address.

For the same reason, "offsetof" is implemented differently on different
platforms.
Actually, maybe using offsetof is the best (standard conforming) way:

template <typename T>
struct size_of
{
struct test
{
T t;
T u;
};

static const int value = offsetof(test, u);
};
Does that always work? Does alignment/packing matter? etc?

Tony

Jul 11 '06 #29

P: n/a
Tony posted:

template <typename T>
struct size_of
{
struct test
{
T t;
T u;
};

static const int value = offsetof(test, u);
};

I already suggested that, but "offsetof" can't be used for a non-POD.

Consider the following specialisation of the structure:

template<>
struct sizeof<std::string{

struct test {

std::string t; /* Non-POD */
std::string u; /* Non-POD */

};

size_t const static value = offsetof(test,u);
/* Opps, working with a non-POD! */
};

--

Frederick Gotham
Jul 11 '06 #30

P: n/a

Frederick Gotham wrote:
Tony posted:

template <typename T>
struct size_of
{
struct test
{
T t;
T u;
};

static const int value = offsetof(test, u);
};


I already suggested that, but "offsetof" can't be used for a non-POD.
Right. forgot. new that seemed too easy...

Tony

Jul 13 '06 #31

P: n/a

Mi*************@tomtom.com wrote:
m_*********@hotmail.com wrote:
(1) The first member of a POD has the same address as the POD itself.
??? A POD has no members...

Wrong. struct X { int a,b } is a POD.
No, X is a POD-struct (that is, each of its members is individually a
POD type) but the X struct itself is not a POD type. X is in fact a
compound type.

Greg

Jul 13 '06 #32

P: n/a
Greg wrote:
Mi*************@tomtom.com wrote:
>m_*********@hotmail.com wrote:
>>> (1) The first member of a POD has the same address as the POD itself.
??? A POD has no members...
Wrong. struct X { int a,b } is a POD.

No, X is a POD-struct (that is, each of its members is individually a
POD type) but the X struct itself is not a POD type. X is in fact a
compound type.

Greg
Nope, it is a POD. POD structs are PODS.
3.9 of the standard
Arithmetic types (3.9.1), enumeration types, pointer types, and pointer
to member types (3.9.2), and cv-qualified versions of these types
(3.9.3) are collectively called scalar types. Scalar types, POD-struct
types, POD-union types (clause 9), arrays of such types and cv-qualified
versions of these types (3.9.3) are collectively called POD types.
Jul 13 '06 #33

This discussion thread is closed

Replies have been disabled for this discussion.