size of a datatype without using sizeof
Asked Answered
S

21

21

I have a data type, say X, and I want to know its size without declaring a variable or pointer of that type and of course without using sizeof operator.

Is this possible? I thought of using standard header files which contain size and range of data types but that doesn't work with user defined data type.

Senegambia answered 2/8, 2009 at 16:22 Comment(10)
What do you mean "of course without using sizeof"? Why of course?Mansfield
I'm supposing because this is an interview riddle for which that answer would defeat the point of the question.Rack
Being a riddle, you have to find an unusual, and possibly absurd, method to do it. See my answer.Glabella
Follow-up question: I want to include a header file I wrote, without using any preprocessor directives, of course. How can I do that?Mansfield
cat foo.h >x.c; cat foo.c >>x.c; gcc x.cGlabella
@John. I believe it's possible to do static linking yourself by malloc'ing function pointers and writing the object code into the memory positions. I have no idea about all the details of doing this though.Procryptic
@John, I actually did that with a horrible shell pipeline once, for a college course that required the assignment to be handed in as a single file. tsort is very much underrated :)Raeleneraf
Why does it matter if this person should use something or not? The question is how to do it without using sizeof and we can either be helpful in answering it or not. Who cares if it'll ruin an interview question? The entire point of this website is to help others out, not to pick apart a question until it conforms to what we want.Ejector
Next in this series: how to obtain the address-of without using an ampersand. Stay tuned!Onto
@Onto how do i do that ? Getting address without ampersand ?Annmarie
O
44

To my mind, this fits into the category of "how do I add two ints without using ++, += or + ?". It's a waste of time. You can try and avoid the monsters of undefined behaviour by doing something like this.

size_t size = (size_t)(1 + ((X*)0));

Note that I don't declare a variable of type or pointer to X.

Osuna answered 2/8, 2009 at 16:40 Comment(16)
This is certainly not standards compliant, but will work on most implementations anyway.Enisle
@Stephano: it may be the most horrible thing you've seen in your life, but it's also more or less how offsetof is typically implemented...Increate
While 0 is guaranteed to mean "null pointer" in all implementations, it doesn't have to be represented internally by address 0, in which case this will fail. The C-FAQ claims that there do exist such machines c-faq.com/null/machexamp.html but they're not anything you're likely to encounter. Clever answer, by the way. :)Rack
Good point, I wonder if there are machines on which (size_t)(1 + ((X*)0) - ((X*)0)) is any more likely to work. Note, I'm using the guaranteed left to right grouping of addition-expression.Osuna
@Charles Balley this question is asked in Cisco interviews. It is not a wastage of time and neither is it a stupid question.Sergei
@CharlesBailey: What if X is a reference? Your solution would not even compile, as pointer to reference is not allowed by C++ Standard.Emilemile
can anybody explain how does that size_t work ? is that similar to casting ?Annmarie
@Annmarie size_t is just an unsigned integer type. The idea here is to have a pointer of the type to inspect pointing at 0, the 1+ operation is done between pointers so the result is 0 incremented by the size of the pointed type. Finally you cast back to size_t. You could as well declare an array of two elements and compute the differences between the two addresses, however this implies a declaration which you can avoid with a cast as above.Memorial
(X*)0 yields a null pointer. Arithmetic on a null pointer has undefined behavior.Vat
@Nawaz: Greetings from the future! The question is tagged C, so we can safely assume X is not a reference.Vat
@KeithThompson: Oops... yes! ((I'm keeping my comment so that others dont ask the same question, or don't apply the same technique directly in C++, as C++'s type-system is a bit more complex))Emilemile
@KeithThompson: "Arithmetic on a null pointer has undefined behavior.". Really? Is it "arithmetic" or "dereferencing" which is undefined behavior?Emilemile
@Nawaz: Both. They're different operations, and both have undefined behavior.Vat
@KeithThompson: I find "arithmetic on null pointer has UB" difficult to believe unless I see a quote from the spec.Emilemile
@Nawaz: N1570 6.5.6, Additive operators: "If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined." (What result would you have expected (int*)NULL + 1 to yield?)Vat
@KeithThompson: Thanks for the quote. That is helpful.Emilemile
P
12

Look, sizeof is the language facility for this. The only one, so it is the only portable way to achieve this.

For some special cases you could generate un-portable code that used some other heuristic to understand the size of particular objects[*] (probably by making them keep track of their own size), but you'd have to do all the bookkeeping yourself.

[*] Objects in a very general sense rather than the OOP sense.

Pallas answered 2/8, 2009 at 16:27 Comment(0)
P
11

Well, I am an amateur..but I tried out this problem and I got the right answer without using sizeof. Hope this helps.. I am trying to find the size of an integer.

int *a,*s, v=10;

a=&v;

s=a;

a++;

int intsize=(int)a-(int)s;

printf("%d",intsize);
Personify answered 5/8, 2009 at 15:3 Comment(1)
But the question asked about doing this without declaring a variable or a pointer to a variable of the type in question....Mungo
P
6

The correct answer to this interview question is "Why would I want to do that, when sizeof() does that for me, and is the only portable method of doing so?"

Pillsbury answered 5/8, 2009 at 15:27 Comment(0)
M
4

The possibility of padding prevent all hopes without the knowledge of the rules used for introducing it. And those are implementation dependent.

Mendy answered 2/8, 2009 at 16:28 Comment(0)
A
4

if X is datatype:

#define SIZEOF(X) (unsigned int)( (X *)0+1 )

if X is a variable:

#define SIZEOF(X) (unsigned int)( (char *)(&X+1)-(char *)(&X) )
Aluminium answered 11/2, 2011 at 11:30 Comment(0)
F
3

You could puzzle it out by reading the ABI for your particular processor, which explains how structures are laid out in memory. It's potentially different for each processor. But unless you're writing a compiler it's surprising you don't want to just use sizeof, which is the One Right Way to solve this problem.

Fr answered 2/8, 2009 at 16:29 Comment(0)
S
3

Try this:

int a;
printf("%u\n", (int)(&a+1)-(int)(&a));
Sharondasharos answered 15/11, 2009 at 8:33 Comment(1)
I have tried this method, but i am getting a warning .. warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] ... Hot to get rid of this ?Annmarie
G
2

Look into the compiler sources. You will get :

  • the size of standard data types.
  • the rules for padding of structs

and from this, the expected size of anything.

If you could at least allocate space for the variable, and fill some sentinel value into it, you could change it bit by bit, and see if the value changes, but this still would not tell you any information about padding.

Glabella answered 2/8, 2009 at 16:26 Comment(3)
The compiler is always free to add additional padding anywhere, so there is no 'expected size' - except for sizeof(char), which is defined to be 1. Note that char may have more than 8 bits, however...Raeleneraf
Can it really be more than 8 bits in C? In C++ it is defined as exactly 1 byte (logic inference: sizeof() returns the size of the argument in bytes, sizeof(char)==1 => char is exactly one byte)Mousey
The word "byte" does not always mean "8 bits". It's basically defined as the smallest individually addressable unit of memory. 8-bit bytes are by far the most common, but there could be (and have been!) systems with 9-bit and even 36-bit bytes, and a system with 32-bit bytes is conceivable, if it doesn't already exist.Tallent
E
1

Try This:

 #include<stdio.h>

int main(){

  int *ptr = 0;

  ptr++;
  printf("Size of int:  %d",ptr);

  return 0;
Enfield answered 6/7, 2013 at 10:55 Comment(0)
P
1

Available since C89 solution that in user code:

  1. Does not declare a variable of type X.
  2. Does not declare a pointer to type X.
  3. Without using sizeof operator.

Easy enough to do using standard code as hinted by @steve jessop

offsetof(type, member-designator)

which expands to an integer constant expression that has type size_t, the value of which is the offset in bytes, to the structure member ..., from the beginning of its structure ... C11 §7.19 3

#include <stddef.h>
#include <stdio.h>

typedef struct {
  X member;
  unsigned char uc;
} sud03r_type;

int main() {
  printf("Size X: %zu\n", offsetof(sud03r_type, uc));
  return 0;
}

Note: This code uses "%zu" which requires C99 onward.

Pederson answered 22/2, 2017 at 0:0 Comment(2)
There may be padding in between the members.Cowpoke
@Cowpoke Padding perhaps. Padding is possible. I would expect that to be rare for an unsigned char.Pederson
D
0

This is the code: The trick is to make a pointer object, save its address, increment the pointer and then subtract the new address from the previous one. Key point is when a pointer is incremented, it actually moves by the size equal to the object it is pointing, so here the size of the class (of which the object it is pointing to).

#include<iostream>
using namespace std;
 class abc
    {
           int a[5];
           float c;           
    };
main()
{
    abc* obj1;
    long int s1;
    s1=(int)obj1; 
    obj1++;
    long int s2=(int)obj1;
    printf("%d",s2-s1);
}

Regards

Dizen answered 7/10, 2012 at 17:44 Comment(0)
C
0

A lot of these answers are assuming you know what your structure will look like. I believe this interview question is intended to ask you to think outside the box. I was looking for the answer but didn't find any solutions I liked here. I will make a better assumption saying

struct foo {
  int a;
  banana b;
  char c;
  ...
};

By creating foo[2], I will now have 2 consecutive foo objects in memory. So...

foo[2] buffer = new foo[2];
foo a = buffer[0];
foo b = buffer[1];

return (&b-&a);

Assuming did my pointer arithmetic correctly, this should be the ticket - and its portable! Unfortunately things like padding, compiler settings, etc.. would all play a part too

Thoughts?

Crowberry answered 9/3, 2013 at 21:3 Comment(0)
A
0

put this to your code

then check the linker output ( map file)

unsigned int  uint_nabil;
unsigned long  ulong_nabil;

you will get something like this ;

uint_nabil 700089a8 00000004
ulong_nabil 700089ac    00000004

4 is the size !!

A answered 24/6, 2017 at 18:48 Comment(0)
P
0

One simple way of doing this would be using arrays. Now, we know for the fact that in arrays elements of the same datatype are stored in a contiguous block of memory. So, by exploiting this fact I came up with following:

#include <iostream>
using namespace std;

int main()
{
    int arr[2];
    int* ptr = &arr[0];
    int* ptr1 = &arr[1];
    cout <<(size_t)ptr1-(size_t)ptr;
}

Hope this helps.

Pestilent answered 3/10, 2017 at 19:27 Comment(0)
C
-1

Try this,

#define sizeof_type( type )  ((size_t)((type*)1000 + 1 )-(size_t)((type*)1000))

For the following user-defined datatype,

struct x
{
    char c;
    int i;
};

sizeof_type(x)          = 8
(size_t)((x*)1000 + 1 ) = 1008
(size_t)((x*)1000)      = 1000
Celik answered 12/11, 2010 at 7:41 Comment(1)
(x*)0 is defined behaviour, (x*)1000 is undefined behaviour.Keyser
N
-1

This takes into account that a C++ byte is not always 8 binary bits, and that only unsigned types have well defined overflow behaviour.

#include <iostream>
int main () {
    unsigned int i = 1;
    unsigned int int_bits = 0;
    while (i!=0) {
        i <<= 1;
        ++int_bits;
    }

    unsigned char uc = 1;
    unsigned int char_bits = 0;
    while (uc!=0) {
        uc <<= 1;
        ++char_bits;
    }

    std::cout << "Type int has " << int_bits << "bits.\n";
    std::cout << "This would be  " << int_bits/8 << " IT bytes and "
              << int_bits/char_bits << " C++ bytes on your platform.\n";
    std::cout << "Anyways, not all bits might be usable by you. Hah.\n";
}

Surely, you could also just #include <limit> or <climits>.

Nada answered 17/6, 2011 at 11:36 Comment(0)
M
-1
# include<stdio.h>

struct node
{
  int a;
  char c;
};

void main()
{
   struct node*ptr;
   ptr=(struct node*)0;
   printf("%d",++ptr);
}
Mincey answered 8/10, 2012 at 16:54 Comment(1)
When adding multiple answers to a question, please include an explanation to them which explains the difference.Bunnybunow
M
-1
#include <stdio.h>

struct {
  int a;
  char c;
};

void main() {
  struct node*temp;
  printf("%d",(char*)(temp+1)-(char*)temp);
}
Mincey answered 8/10, 2012 at 17:0 Comment(0)
A
-1
    main()    
    {
    clrscr();
    int n;
    float x,*a,*b;//line 1
    a=&x;
    b=(a+1);
    printf("size of x is %d",
    n=(char*)(b)-(char*)a);
    }

By this code script the size of any data can be calculated without sizeof operator.Just change the float in line 1 with the type whose size you want to calculate

Apocryphal answered 29/3, 2015 at 16:13 Comment(0)
P
-2
#include <bits/stdc++.h> 

using namespace std; 

int main() 
{ 

    // take any datatype hear 
    char *a = 0; // output: 1

    int  *b = 0;  // output: 4

    long *c = 0; // output: 8

    a++;

    b++;

    c++;

    printf("%d",a);

    printf("%d",b);

    printf("%d",c);

    return 0; 
}
Perennial answered 10/9, 2018 at 11:34 Comment(2)
The question asks how to do this "without declaring a variable or pointer of that type...."Mungo
There are multiple issues with that answer. It uses a pointer which is not valid according to the question. It is C++ while there is only a C language tag and it also invokes undefined behaviour when printing a pointer with "%d" format specifier.Haletky

© 2022 - 2024 — McMap. All rights reserved.