When compiling, C discards[1] most type information, leaving only offsets. So, your function would compile to something like this, in pseudocode:
changeCount:
assign *(*(stack_ptr + offset_element) + offset_Count) + 1
to *(stack_ptr + offset_element) + offset_Count;
assign 1 to return_value;
pop
The stack_ptr is the location of the stack frame that was created when you call changeCount, the offset_element is the location of the element argument, relative to the stack_ptr, but what is offset_Count? Keep in mind, all the compiler knows about your code is just what you have shown in your example; element is a generic pointer, not really a pointer to anything. You will have to tell the compiler what element is pointing to, by casting or assigning it to a variable[2]:
typedef struct { int Count; } counted_t;
int changeCount(void* element)
{
counted_t* counted = element;
counted.Count++;
return 1;
}
This function will generate essentially the same (pseudo)code as above, but the compiler now knows what the offset of Count should be.
You mention that there are three possibilities for the type of what element is pointing to. There are a couple of ways of handling that: either a distinguished union or an "inherited" structure. For a distinguished union use, say, a structure with one element being an enum identifying which of the three possibilities and another element being a union of the three possible structures; this is roughly what the ML languages (OCaml, Haskell, etc.) call an algebraic data type or what a union is in Pascal. For "inheritance", you could use type definitions:
typedef struct { counted_t counted; int i; } counted_int_t;
typedef struct { counted_t counted; double d; } counted_double_t;
typedef struct { counted_t counted; char* s; } counted_charptr_t;
In this case, you could use the changeCount function above and pass in a pointer to a counted_int_t, counted_double_t, or counted_charptr_t.
What happens is that the compiler will lay out the three structures with the Count element in the "descendant" structures in the same place as long as the counted_t element is first. (At least, in every compiler I have ever used and in every bit of code I have seen. I think this made it into the C standard at some point, but it is a very normal idiom.)
[1] Except for debugging information, if you have told the compiler to emit it. Your program will not have access to that information, though, so it would not help in this case.
[2] The x++ (postincrement) operation increments the variable (well, lvalue) that it is applied to; the assignment in the original code is unnecessary.