3

我可以将指向结构的指针类型转换为有符号值以返回不同类型的错误。C 标准是否允许这样做或者是未定义的行为。

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");

}

我怎样才能使这种情况起作用?

4

3 回答 3

4

C 标准“允许”这样做,但不支持。也就是说,如果您尝试这样做,它不会定义发生的行为。如果您尝试这样做,您的 C 实现也可能不会定义发生的行为。

不要这样做。

您可以通过创建实际对象来合法地完成这项工作:

DATACARD okay, error, abort, halt

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

如果DATACARD更大并且您不想为这些额外的对象浪费空间,还有其他可用的技术。通常,类似例程getCard会被定义为NULL在发生错误时返回并通过单独的机制提供错误代码,例如指向存储错误代码的位置的附加参数。

于 2013-10-02T14:25:37.707 回答
3

UNIX sbrk() 函数依赖于这种工作方式,因为它返回 -1 作为指针值以指示特定情况。因此,虽然 C 标准不能保证它会起作用……但它会起作用。

但是,为了比较值,总是将指针转换为整数类型,而不是相反。这将避免 64 位系统上的位宽问题,并确保您在签名上下文中执行操作。

于 2013-10-02T14:26:59.897 回答
0

这是未定义的行为

规范(如下)有点长,但关键是getCard()返回的值如(DATACARD *) some_int. 它some_int可能不是负数,它可以是除 0 之外的任何整数,但仍然存在问题。由于返回值可能不是基于实际存在的类型变量(DATACARD *)而不是 NULL,因此任何此类比较都是未定义的。

推荐使用@Eric Postpischil:

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

此外,(DATACARD *) -1结果不一定是“负”指针。我发现没有 C 规范可以确认指针是否要签名、未签名或两者之一。(规范可能存在。)-1当然是负的,但这种派生指针的符号性是不确定的。

C11dr 6.5.8 5“当比较两个指针时,结果取决于指向的对象在地址空间中的相对位置。如果两个指向对象类型的指针都指向同一个对象,.. 或者如果对象指向是同一个聚合对象的成员,......在所有其他情况下,行为是未定义的。”

于 2013-10-02T20:26:49.277 回答