14

How do you check if a pointer is of a certain type?

Using sizeof is not sufficient.

I am trying to avoid putting id-numbers into my structs to identify their type. The assumption is that maybe gcc puts a struct definition somewhere in the process, and maps the definition to the allocated memory at a pointer. If this is true, I'd think there would be someway to check for a pointers type.

unwind
  • 391,730
  • 64
  • 469
  • 606
Crazy Chenz
  • 12,650
  • 12
  • 50
  • 62
  • why would you want to avoid putting idnumbers in your structs ? – LB40 Jun 04 '09 at 14:50
  • The compiler does all the type checking, then basically throws it all away in the generated code. Everything is more or less converted to addresses and offsets of addresses. It is also perfectly legal (though generally bad form) to cast one pointer type to another, completely unrelated, type. – Dolphin Jun 04 '09 at 15:04
  • 1
    You shouldn't need to embed the type information with the pointer; you should keep track of the information in the program, so when your function expects a pointer to integer, you do not pass it a pointer to a double, etc. And if you're using void pointers everywhere, then it is up to you to keep track of things, perhaps by using some convention (like type information field is first item in data structure) and then testing it. But that is harder work than keeping things straight in the first place. – Jonathan Leffler Jun 04 '09 at 15:45

11 Answers11

40

You can't.

A pointer merely stores an address and nothing related to the contents of that address.

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
14

"I am trying to avoid putting idnumbers into my structs to identify their type." Don't avoid that. If you really want to be able to check type, put a typeID as the first element of every struct. Your impulse was not a bad one.

Nosredna
  • 83,000
  • 15
  • 95
  • 122
9

Gcc does not put the structure definition anywhere in the runtime. This means you cannot as standard.

It can depend on what you are using the type information for. Two major applications might be:

  1. Debugging or similar runtime inspection
  2. Serialization and Deserialisation of datastructures

In the first case there information is often available stored in the symbols output by the compiler and attached to the executable (in many environments).

The implementation is platform specific and often means the compiler needs to be instructed to output this information. One example of a program doing this is gdb. Pointers still have to be typed correctly for this to be useful.

For serialisation types are often tagged with values like you suggest. These tags don't though have to be stored with the in-memory data. They can be added by the output routine.

andygavin
  • 2,784
  • 22
  • 32
  • http://stackoverflow.com/questions/1241205/are-all-data-pointers-of-the-same-size-in-one-platform Doesn't this discussion negate your answer to a certain extent regarding sizeof() operator. – Coder Sep 12 '13 at 14:30
  • Not really the intent was to describe the sizeof operator and why it doesn't work. Not suggest that the size could be used to imply the type. I've edited my answer as it's quite old and unclear. Thanks. – andygavin Sep 12 '13 at 23:13
7

Pointer is the type. More generally, C doesn't provide the ability to do introspection. There's no programmatic way to determine the type of a variable.

Michael Carman
  • 30,628
  • 10
  • 74
  • 122
6

All of the answers posted here say "you can't." They're right. You can't.

But, and I hesitate to even mention it, there are games that can be played. These games are a bad idea. I do not recommend them in any situation.

What's the game? Stuffing steaky extra data bits into unused parts of the address, and stripping them out wherever you use the address.

So imagine you have pointers to a structure or class that's 32 bytes in size. If you make sure your memory allocations are aligned to a 32 byte address, (which is easy for dynamic allocations but trickier to guarantee for stack ones), the low order bits of the address will all be 0. This means there's 5 free bits at the bottom of the address, enough for you to put flags, ID numbers, status values, etc. The storage is free! Even if you have an odd structure size, virtually any C or C++ compiler and OS will always align every address to 4 bytes.

In 64 bits, you can usually find a significant number of free bits at the high end of addresses... very likely 16 free unused bits, waiting for you. This is OS dependent of course. And also a bad bad idea to consider. You like danger, don't you?

The two downsides are:

  1. You have to make sure to mask the values out before you try to dereference the pointer, or pass it to anything that may try. This makes ugly code.
  2. You are dancing beyond the edge of the unportability cliff of stupid dangers. This is like drinking a bottle of tequila and walking a frayed tightrope over hungry tigers. Nude.

Your fate if you follow my advice
(source: ecoworldly.com)

There's so many ways that this will explode into bugs, crashes, and pain. Remember how I said that compilers align memory to at least 4 bytes? Well, that's true. Until you find a new OS that doesn't. And you're tiger food.

So don't do this.

But, that said, it is indeed a way to stuff a little extra info like a type number into every address. You may see this technique in every-byte-counts code, or Obfusicated C.

PS: Really, I mean it, don't do this. Even if you like tigers.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
SPWorley
  • 11,550
  • 9
  • 43
  • 63
  • 1
    Guile (the Scheme implementation) uses something like this ( http://www.gnu.org/software/guile/manual/html_node/Faster-Integers.html ) – Max Lybbert Jun 05 '09 at 22:42
  • @max, great example! I think Emacs used to do it 15+ years ago too, and it was a huge pain to un-do when they needed to scale to modern memory sizes. – SPWorley Jun 05 '09 at 23:25
4

No, there's no runtime type information anywhere.

You should write your functions so that the function signature carries the type information and let the compiler check the types statically. For example void burp_foo(struct foo *thefoo) tells that the argument is a pointer to a struct foo. It is up to the caller to supply one. Of course, through type casting it is possible supply any pointer as pointing to a struct foo but then it's the caller's problem, not yours.

laalto
  • 150,114
  • 66
  • 286
  • 303
2

You can't do that in C. Actually the C++ compiler does something like what you want (storing information about the type of a class to the allocated memory). In C you have no classes, but only structs, which contain no overheads whatsoever.

kgiannakakis
  • 103,016
  • 27
  • 158
  • 194
  • Even in C++ this is stored only for polymorphic classes (classes with virtual functions). In other cases compile time information needs to be used. – Suma Jun 05 '09 at 15:56
2

A way to avoid putting a ID member in your struct is to use polymorphism like :

typedef struct {
        char const *name;
        int id;
        /* ... */
} object_info_t;

typedef struct {
        object_info_t *info;
} object_t;

typedef struct {
        object_t object;
        int a;
} foo_t;

typedef struct {
        object_t object;
        int b;
} bar_t;

int object_get_id(object_t *object)
{
        return object->info->id;
}

Note you can augment object_info_t with function pointers and avoid checking ids altogether :

typedef struct {
        char const *name;
        int id;
        int (*do_something)(object_t *);
} object_info_t;

int object_do_something(object_t *self)
{
        return self->info->do_something(self);
}
diapir
  • 2,872
  • 1
  • 19
  • 26
1

There's nothing like this in C. A pointer is either of a specific type or it is void*. There's no function overloading or built-in runtime polymorphism like in C++. You can though do pseudo object oriented tricks using function pointers, like:


typedef void (*cmd_func)( int );
struct command
{
    int      arg;
    cmd_func action;
};
Nikolai Fetissov
  • 82,306
  • 11
  • 110
  • 171
0

Well one possible way would be to save the pointer address and increment the pointer to see the new address of it. The difference will give a hint.

Megharaj
  • 1,589
  • 2
  • 20
  • 32
0

The C standard does not allow this directly. The C++ standard has some ability to do this (dynamic_cast and typeid).

typeof

GCC comes with a typeof operator that may be useful depending on what you're doing.

conditional operator

The conditional operator (the question mark and colon in expressions like x = y == 0 ? 1 : 0;) has some ability to tell you if two types can be coerced into a third type (that article is about C++, but the type safety of the conditional operator is the same in C). Its use is nonobvious to say the least.

Both of these techniques (typeof and the conditional operator) are limited to what information is available at compile time. That is, you can't pass a void* to a function and then use typeof to figure out the original type of the object the pointer points to inside that function (because such information isn't available inside that function at compile time).


Thinking more about this, GTK+ is written in C and has a system you may consider emulating. It looks like they use type IDs, but instead of putting the IDs in the struct, they use macros to look things up.

Max Lybbert
  • 19,717
  • 4
  • 46
  • 69