3

Can i typecast a pointer to a structure to a signed value to return a different types of errors. Does the C standard allow this or is an undefined behaviour.

typedef enum lError
{
  l_OK = 0,
  l_ERROR = -1,
  l_ABORT = -2,
  l_HALT = -3
}L_STATUS;


typedef struct dataCards
{
  int card1;
  int card2;
  char flag;
}DATACARD;

DATACARD dataCardG;

DATACARD *getCard(int i)
{
  if(i == 1)
    return &dataCardG;
  else if (i == 2)
    return (DATACARD *)l_ERROR;
  else if (i==3)
    return (DATACARD *)l_ABORT;
  else
   return (DATACARD *)l_HALT;

}

int main ()
{
  DATACARD *ptr = NULL;

  ptr = getCard(3);
  if(ptr < (DATACARD *) 1)   /* Is this allowed or undefined behaviour */
    printf("Card failed\n");

}

How can i make this condition work?

powernest
  • 261
  • 1
  • 2
  • 12

3 Answers3

4

The C standard “allows” this, but it does not support it. That is, it does not define the behavior that occurs if you try this. Your C implementation also likely does not define the behavior that occurs if you try this.

Do not do this.

You could make this work legitimately by creating actual objects:

DATACARD okay, error, abort, halt

#define Okay  (&okay)
#define Error (&error)
#define Abort (&abort)
#define Halt  (&halt)

If DATACARD were larger and you did not want to waste the space for these extra objects, there are other techniques available. Often, a routine like getCard would be defined to return NULL in case of error and to provide an error code via a separate mechanism, such as an additional parameter pointing to a place to store an error code.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Or have your function return the error code by value as an additional parameter would work as well if you don't want a global and don't mind editing a bunch of signatures. 100% agree with sentiment, you should return NULL here and have some other avenue for finding out why it failed. Principle of least surprise and consistency, every other function returning a pointer returns NULL or throws an exception to indicate failure.. :-) – UpAndAdam Oct 02 '13 at 15:01
3

The UNIX sbrk() function relies on this working, in that it returns -1 as a pointer value to indicate a particular situation. So while the C standard doesn't guarantee it'll work.... it'll work.

For comparing the values, though, always cast the pointer to the integer type, not the other way around. That'll avoid bitwidth problems on 64-bit systems, and make sure you're doing things in a signed context.

Sneftel
  • 40,271
  • 12
  • 71
  • 104
  • 1
    (a) `sbrk` derives from an earlier time when programming standards were younger; it is not a good model for today. (b) The return value of `sbrk` implies that a –1 pointer value is supported in C implementations that support `sbrk` but does not imply it for C implementations generally nor that other integer values are supported. – Eric Postpischil Oct 02 '13 at 14:32
0

This is undefined behavior.

The spec (below) is a bit long, but the key is that getCard() returns values like (DATACARD *) some_int. Its not that some_int may be negative, it could be any integer aside from 0 and still pose problem. Since the return value may not be based on a real existing variable of type (DATACARD *) and not NULL, any such comparison is undefined.

Recommend using @Eric Postpischil:

DATACARD okay, ...
#define Okay  (&okay)

Further, (DATACARD *) -1 does not necessarily result is a "negative" pointer. I have found no C spec that affirms if pointers are to be signed, unsigned or either. (Spec might exist.) The -1 is certainly negative, but the sign-ness of such a derived pointer is not certain.

C11dr 6.5.8 5 "When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object types both point to the same object, .. or If the objects pointed to are members of the same aggregate object, ... In all other cases, the behavior is undefined."

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256