强制转换返回强制类型的函数的返回值

时间:2020-08-26 12:37:57

标签: c arm embedded

我想从编译器的角度知道将强制类型转换为返回转换值的函数会发生什么情况。我想知道显式类型转换返回值的优点和缺点。

static uint16_t sResult_U16;

static uint16_t GetMyResult(void) 
{
    return (uint16_t)sResult_U16;
}

vs

static uint16_t GetMyResult(void) 
{
    return sResult_U16;
} 

如果返回类型与函数类型不同,编译器将翻译什么?例如。

static int16_t sResult_S16;

static uint16_t GetMyResult(void) 
{
    return sResult_S16;
}

3 个答案:

答案 0 :(得分:1)

从编译器的角度来看,(uint16_t)sResult_U16;毫无意义,因为sResult_U16的类型已经与返回类型相同。在第一种情况下,它只会忽略无用的强制转换。

在第二种情况下,您使用的类型与返回类型不同。然后,将变量转换为与返回类型相同的类型,这实际上是通过获取带符号变量的原始二进制表示形式并将其转换为与原始二进制无符号等效项来实现的(详细的正式规则在底部引用)这个答案)。


有关详细信息,请参见C17 6.8.6.4/3,其中指出:

如果表达式的类型不同于它所出现的函数的返回类型,则该值的转换就好像是通过分配给具有函数的返回类型的对象一样。

“好像是通过赋值”是重要的部分-这与使用=时的规则相同。因此,我们必须查找分配6.5.15.1的规则:

简单赋值(=)中,将右操作数的值转换为赋值表达式的类型,并替换存储在由左操作数指定的对象中的值。

这种转换是隐式发生的,不需要强制转换-示例中的强制转换只是混乱。

在特定情况下,会发生从有符号到无符号的整数转换(6.3.1.3):

否则,如果新类型是无符号的,则通过重复加或 比新类型可以表示的最大值多减去一个 直到该值在新类型的范围内。

答案 1 :(得分:0)

return语句就像通过赋值一样工作,这意味着

FOO bar(void) 
{
    ...
    return baz;
}

相同
FOO bar(void)
{
    ...
    FOO return_value;
    return_value = baz;
    return returnValue;
}

return baz;仅在分配return_value = baz;有效时有效。

现在,对于赋值(对于return同样),右操作数的值将转换为左操作数的值,因此,如果您的函数返回uint16_t,则表达式中的值将使用语言规则将return语句转换为uint16_t

如果没有显式强制转换的情况下到uint16_t的转换是有效的(对于整数和实数浮点类型也是如此),则强制转换为(uint16_t)不会有任何改变。但是,指针没有隐式转换为整数,因此,如果您尝试执行 advised 事情并从强制转换为uint16_t的该函数返回指针,则需要显式演员。

从上面可以得出结论:

static int16_t sResult_S16;

static uint16_t GetMyResult(void) 
{
    return sResult_S16;
}

进行了组装,以便通过将有符号整数转换为模数65536的正数来将其转换为无符号整数。在实践中,由于您恰好使用了int16_tuint16_t,因此转换将导致完全相同的位表示,但可能为零扩展。

答案 2 :(得分:0)

我们可以将这种情况分为三种情况:

  1. 如果return表达式的类型与函数的返回类型相同,则将其返回到调用方,而无需进行更改。
  2. 如果return表达式的类型不同,但根据某些约束条件它是相似的,它将自动转换为函数的返回类型。
  3. 如果return表达式的类型超出约束,则编译器将抱怨。编译器可能会或可能不会继续编译程序,具体取决于多种因素。

这对return表达式中的类型转换意味着什么:

  1. 强制转换为函数的返回类型无效,因为表达式已经是必需的类型。因此这是不必要的。
  2. 强制转换为函数的返回类型将具有与无论如何都会发生的自动转换相同的效果。因此这是不必要的。
  3. 强制转换为函数的返回类型是避免编译器警告的必要条件。这种转换是否正确取决于情况。有强制转换已定义并具有所需的行为,但不会自动执行,但也可能具有未定义或不良行为。

C 6.8.6 4 3说:“…如果表达式的类型不同于它所出现的函数的返回类型,则该值的转换就好像是通过分配给具有该函数的返回类型的对象一样。 ” C 6.5.16.1 1指定了分配约束。为简化起见,它们允许:

  • 将数字类型分配给数字类型。
  • 将结构或联合类型分配给兼容的结构或联合类型。
  • 将类型的指针分配给具有至少相同的限定符(constvolatilerestrict_Atomic)的兼容类型的指针。 / li>
  • 使用至少相同的限定词将指向void的指针分配给对象类型的指针,反之亦然。
  • 将空指针常量分配给指针。
  • 分配一个指向_Bool的指针。

已定义但未自动执行的转换示例是将int *转换为char *。如果声明为返回char *的函数已经在int *x中计算了某个值并想返回它,则它不能使用return x;,因为它不满足上面列出的任何约束。但是,(char *) x是由C 2018 6.3.2.3 7定义的,因此可以使用return (char *) x;

请注意,尽管编译器必须接受满足所列约束之一的return表达式,但它可能会产生警告。也就是说,它可以显示一条消息,警告用户可能不希望发生的事情,例如返回double,其中返回类型为int,因此可能会丢失信息,但C标准要求编译器以继续继续编译程序。