如果运行以下 C 代码会发生什么?

问题描述 投票:0回答:1
printf("%d\n", (1 ? (int)1 : (double)1.1));

结果不是 1,而是一个随机整数(在 Windows10 上的 wsl 上运行)。比如

-2031766944
201011808

当我想使用以下方式实现动态或重叠变量时,我发现这个问题:

typedef enum _DataType
{
    INT,
    DOUBLE
} DataType;

typedef union _Data
{
    int int_;
    double dou_;
} Data;

typedef struct _Number
{
    DataType datatype;
    Data data;
} Number;

因为C是静态类型。没有函数可以获取

Number
的实际值。所以我尝试了这样的宏函数:

#define GETVAL(param) (((param).datatype == INT) ? (param).data.int_ : (param).data.dou_)

但是该函数似乎只能返回double类型。而我在调试的时候,发现了上面的问题。

c
1个回答
0
投票

在 C 语言中,三元条件运算符

(?:)
的形式为:

condition ? expression_if_true : expression_if_false

关键点是

expression_if_true
expression_if_false
都必须产生兼容的类型。如果类型不同,则应用“常规算术转换”将它们转换为通用类型。

在你的例子中:

(0 ? (int)1 : (double)1.1)

由于

0
为 false,因此表达式的计算结果为
(double)1.1
。两种可能的表达是
(int)1
(double)1.1
。由于类型提升规则:

  • int
    double
    用于同一表达式时,
    int
    会提升为
    double

  • 因此,三元表达式的整体类型为

    double

此外,您在

%d
中使用
printf
作为格式说明符,它需要
int
。但是,由于三元运算符中的类型提升,您传递的是双精度值。

这种不匹配会导致未定义的行为,因为

printf
读取堆栈(或寄存器,具体取决于调用约定),期望得到
int
,但这些位对应于
double
。这会导致垃圾输出或随机整数。

  • 确保类型一致性:确保值的类型与

    printf
    中的格式说明符匹配。

  • 使用适当的格式说明符:如果结果是

    double
    ,请在
    %f
    中使用
    %lf
    printf

    printf("%f ", (0 ? (双)1 : (双)1.1));

或者,如果您总是想要

int

printf("%d\n", (0 ? 1 : (int)1.1));
  • 关于你的宏

    #define GETVAL(param) (((param).datatype == INT) ? (param).data.int_ : (param).data.dou_)

根据三元运算符的规则,如果

(param).data.dou_
double
,并且
(param).data.int_
int
,则
int
将提升为
double
。因此,
GETVAL(param)
将始终返回
double

每种类型都有单独的宏或函数,根据情况使用适当的宏

param.datatype

#define GETVAL_INT(param) ((param).data.int_)
#define GETVAL_DOUBLE(param) ((param).data.dou_)
© www.soinside.com 2019 - 2024. All rights reserved.