6

Is there in C, or at least in GCC, some way of making (with typedef) a type that is incompatible with any other type?

For example, you make:

typedef UINT UID;
typedef UINT AGE;

UID user_id;
AGE user_age;

You can see that both types are unsigned int (I name it UINT).

You can calculate user_id + user_age.

BUT, you want to be sure UIDs and AGEs will never be mixed.

That's what I want!

The idea is for the security and correctness of the code, to specify some qualifier/attribute for some types.

Than, the ONLY way to mix them will be casting both to UINT, or casting user_age to UID, for example.

C language can be very confuse, and sometimes we take HOURS just to find out that silly bug is there just because you used the wrong value as an argument because the variables have similar names... and the compiler obviously will never complain, because they have the same type.

I didn't find any atttribute for this in the GCC manual, but I'm going to request it in the mailing list.

I just want to know HOW (and I know there isn't, the real question I have is WHY the standard and the compiler doesn't provide this, as I see it as really useful and relatively one of the most easy things to implement at the compiler side) to specify some ATTRIBUTE on a type (and also on variables) to tell the compiler that TYPE is not supposed to be mixed with any other, unless explicitly casted to it. So the real question here is: - Why is this a bad idea? (Why no compiler consider it?) - Would you also use it if this GCC attribute existed? Oh... in my opinion I would use it here and there, just put this attribute in almost all typedefs and then just program; a HUGE part of the mistakes would be detected at the first compilation - passing arguments in the wrong order, using the wrong variable in a big and complicated calculation...

Sorry for my bad english.

user3525723
  • 313
  • 1
  • 8
  • 1
    Use `struct` with different tags to create incompatible types. – ouah Sep 15 '14 at 16:14
  • 2
    Nitpicking: "*You can se[e] that both types are unsigned int.*" They are not. Both are of type `UINT`, whatever this might be defined to be. `UINT` is not a type defined by the C Standard. – alk Sep 15 '14 at 16:19
  • Related: http://stackoverflow.com/questions/4669454/how-to-make-gcc-warn-about-passing-wrong-enum-to-a-function – alk Sep 15 '14 at 16:34
  • 2
    This feature is called "strong typedef", which should give you some more hints when searching the web. – Ulrich Eckhardt Sep 15 '14 at 17:31
  • It's not quite accurate to say that "both types" are `unsigned int`. Assuming that `UINT` is a typedef for `unsigned int`, *there is only one type here*. That one type happens to have at least 4 different names: `unsigned int`, `UINT`, `UID`, and `AGE`. `typedef` doesn't create a new type, compatible or otherwise; it merely creates a new name for an existing type. – Keith Thompson Sep 15 '14 at 17:46
  • @alk and Keith Thompson: I know, I know... "UINT" is defined by me as unsigned int, and I used it to be the most clear as possible in the example. – user3525723 Sep 16 '14 at 18:56

2 Answers2

5

Assuming that UINT is defined as some type you can create typedefs for them to make them incompatible. The code below gives an idea how you initialize and manipulate them.

typedef struct { UINT id; } UID;
typedef struct { UINT age; } AGE;

UID user_id = { 1234 }; /* Example of initialization of a struct */
AGE user_age = { 23 };

int main()
{
    UINT add;
    user_age.age = 25; /* example of assignment */
    add = user_id + user_age; /* Example of compile error */

    return 0;
}

There are some downsides as well. You can't use structs with operators (+,-,/,* etc). ie. You can't add two structs together. Because of that this wouldn't work:

AGE user1age = { 25 };
AGE user2age = { 23 };
UINT totage = user1age + user2age;

You'd have to do it this way and explicitly add the age values in the structs:

AGE user1age = { 25 };
AGE user2age = { 23 };
UINT totage = user1age.age + user2age.age;
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
4

Use structs:

typedef struct 
{
  unsigned int uid;
} UID;

typedef struct
{ 
  unsigned int age;
} AGE;

UID user_id;
AGE user_age;
alk
  • 69,737
  • 10
  • 105
  • 255