Enumerate the basic data types in C so that the sizes can be easily accessed


Enumerate the basic data types in C so that the sizes can be easily accessed



Is it possible to get sizes of all basic datatypes in C using a for loop? For example, can we do something like this?


#include <datatypes.h> /* or something else which defines get_data_types() */
#include <stdio.h>

int main() {
for (int x = 0; x < len(get_data_types()); x++) {
printf("Size of %s is %d", get_data_types()[x], sizeof(get_data_types()[x]));
}
}



I could enumerate all the datatypes by replacing the for loop and writing individual statements for int, long, etc. However, I am wondering if it is possible to have a for loop to do the same?


int


long



Essentially, I am trying to avoid the following:


#include <stdio.h>

int main() {
printf("Size of int is %d", sizeof(int);
printf("Size of unsigned int is %d", sizeof(unsigned int);
printf("Size of long is %d", sizeof(long);
/* etc. */
return 0;
}



Data types of interest - char, unsigned char, signed char, int, unsigned int, short, unsigned short, long, unsigned long, float, double, long double


char


unsigned char


signed char


int


unsigned int


short


unsigned short


long


unsigned long


float


double


long double



Clarification: I don't necessarily want an array of mixed types, but to be able to enumerate the types so that the sizes can be easily accessed.





You cannot mix datatypes in an array in C. Well, you can achieve something similar by trickery, but you cannot get the type of a particular place in memory.
– klutt
Jul 1 at 2:42





C has an infinite number of data types: int, int*, int**, int***, ..., int[1], int[2], ..., enum A, enum B, struct A, struct B, .... Do you mean basic/arithmetic types?
– aschepler
Jul 1 at 2:50


int


int*


int**


int***


int[1]


int[2]


enum A


enum B


struct A


struct B





@aschepler Yes, I meant that. I edited the question to reflect that.
– Nipun Batra
Jul 1 at 3:07





@klutt I get it. What's the easiest workaround?
– Nipun Batra
Jul 1 at 3:07





The work around is to list the types you want sizes of and compute their sizes. The number of "basic" types (in the sense of not defined in terms of one or more another types) is pretty small. The number of derived types (defined in terms of one or more other types) approaches infinity (e.g. struct and enumerated types, pointers, arrays (of different sizes - each size has a different type) of all basic and derived types, etc).In practice, you will only need sizes of basic types (like int, float, etc) and a few derived types (structs, pointers, arrays, etc).
– Peter
Jul 1 at 3:43


int


float




3 Answers
3



Nope, it's not possible. There's no way to automatically list all types in C. You have to do this manually for each type.



However, if you are using the information a lot, you can always prepare a list in advance. There are some ways to do it. This is one:


#include <stdio.h>
#include <string.h>

typedef struct {
char name[20];
int size;
} type;

int main()
{
type types[3] = { {"int", sizeof (int) },
{"char", sizeof (char) },
{"double", sizeof (double) } };

for (int x = 0; x<sizeof(types)/sizeof(types[0]); x++)
printf("Size of %s is %dn", types[x].name, types[x].size);
}



(Code simplified with inspiration of Paul Ogilvie's answer below.)



In a comment to this answer you asked: Can we just create an array like the following : types_array = {"int", "char", "double", "long"} and while iterating over this get the corresponding sizes? I mean to say using some function f, can we assign types[j].size to sizeof(f(types_array[j]))



In short, no. This is because C is a strongly typed compiled language. In languages like Python and PHP you can do all sorts of fancy stuff like that, but in C no. Not without trickery. The function f in your example must have a specified return type, and this is the type sizeof will get as argument.


f


sizeof



One way to get around it is to write a custom sizeof:


int mysizeof(char * s) {
if(strcmp(s, "char") == 0)
return sizeof(char);
if(strcmp(s, "int") == 0)
return sizeof(int);
}



If this list is long, you could use a macro:


#define MYSIZEOF(x) if(strcmp(s, #x) == 0) return sizeof(x)

int mysizeof(char * s) {
MYSIZEOF(int);
MYSIZEOF(char);
MYSIZEOF(double);
}





Many thanks @klutt. This looks reasonable. Can we just create an array like the following : types_array = {"int", "char", "double", "long"} and while iterating over this get the corresponding sizes? I mean to say using some function f, can we assign types[j].size to sizeof(f(types_array[j]))
– Nipun Batra
Jul 1 at 6:38


f





@NipunBatra No, you cannot. Such things cannot be done in a strongly typed compiled language.
– klutt
Jul 1 at 15:30





Many thanks! Accepted the answer :)
– Nipun Batra
Jul 2 at 11:23



Your approach is not possible, the various types must be enumerated explicitly, one way or another, but you can make an array of structures, use a convenience macro to intialize it simply and write a loop to output all standard type sizes.



Note that you forgot a few useful standard types:


long long


unsigned long long


size_t


ptrdiff_t


intmax_t


uintmax_t


wchar_t


void *


char *


int *


void(*)(void)



Here is an implementation:


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

#define TYPEDESC(t) { #t, sizeof(t) }

static struct type_desc {
const char *name;
int size;
} const types = {
TYPEDESC(char), TYPEDESC(unsigned char), TYPEDESC(signed char),
TYPEDESC(wchar_t),
TYPEDESC(short), TYPEDESC(unsigned short),
TYPEDESC(int), TYPEDESC(unsigned int),
TYPEDESC(long), TYPEDESC(unsigned long),
TYPEDESC(long long), TYPEDESC(unsigned long long),
TYPEDESC(float), TYPEDESC(double), TYPEDESC(long double),
TYPEDESC(size_t), TYPEDESC(ptrdiff_t),
TYPEDESC(intmax_t), TYPEDESC(uintmax_t),
TYPEDESC(void *), TYPEDESC(char *), TYPEDESC(int *),
TYPEDESC(void (*)(void)),
};

int main() {
size_t i;
for (i = 0; i < sizeof(types) / sizeof(types[0]); i++)
printf("sizeof( %s ) = %dn", types[i].name, types[i].size);
return 0;
}



The output on my 64-bit OS/X system is this:


sizeof( char ) = 1
sizeof( unsigned char ) = 1
sizeof( signed char ) = 1
sizeof( wchar_t ) = 4
sizeof( short ) = 2
sizeof( unsigned short ) = 2
sizeof( int ) = 4
sizeof( unsigned int ) = 4
sizeof( long ) = 8
sizeof( unsigned long ) = 8
sizeof( long long ) = 8
sizeof( unsigned long long ) = 8
sizeof( float ) = 4
sizeof( double ) = 8
sizeof( long double ) = 16
sizeof( size_t ) = 8
sizeof( ptrdiff_t ) = 8
sizeof( intmax_t ) = 8
sizeof( uintmax_t ) = 8
sizeof( void * ) = 8
sizeof( char * ) = 8
sizeof( int * ) = 8
sizeof( void (*)(void) ) = 8



It may come as a surprise that wchar_t is 32-bits and long double 16 byte long. This does not mean that long double values use all 128 bits for the floating point representation. The output will be very different on a Windows system.


wchar_t


long double


long double





However, for instance sizeof (char*) == sizeof(int(*)(double, long)) will always evaluate to true.
– klutt
Jul 1 at 16:25



sizeof (char*) == sizeof(int(*)(double, long))





@klutt: I don't think so: function pointers may be smaller than generic pointers on some architectures. It used to be the case on x86 segmented architectures in Medium mode, small code+large data. Is there something in the C Standard that supports your statement?
– chqrlie
Jul 1 at 17:09





Oh, I did not know that. Interesting. I did suspect that the C standard for obvious reasons did not dictate that all pointers should have the same size, but I thought that in practice that were the case.
– klutt
Jul 1 at 17:34





@klutt: the C Standard does not mandate that pointers to different types have the same size. Pointers to char may for example be larger than pointers to int, as was the case on older Cray computers. In practice, for user code, it is almost always the case, and it is mandatory on POSIX systems.
– chqrlie
Jul 1 at 21:48



char


int





Many thanks. Really useful :)
– Nipun Batra
Jul 2 at 11:23



Klutt's answer can be a bit simplified to:


struct {
char *name;
int size;
} types = {
{"int", sizeof(int)},
{"char", sizeof(char)},
{"long", sizeof(long)}
//.. etcetera
};

int main(void) {
int i;
for (i=0; i<sizeof(types)/sizeof(types[0]); i++)
printf("sizeof %s = %dn",types[i].name, types[i].size);
return 0;
}





Nice! I referenced this answer, because I did not want to steal it.
– klutt
Jul 1 at 15:30





@Klutt, yea, it is all static/compile time. Should make it to const char *name as the literal will be read-only.
– Paul Ogilvie
Jul 1 at 15:47


const char *name





Many thanks. Very informative :)
– Nipun Batra
Jul 2 at 11:23






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

List of Kim Possible characters

Audio Livestreaming with Python & Flask

NSwag: Generate C# Client from multiple Versions of an API