【问题标题】:unsigned int data types in cc中的无符号int数据类型
【发布时间】:2014-07-02 15:09:19
【问题描述】:

请帮助我区分 C 中的这些代码:

代码 1:

#include<stdio.h>
#include <stdint.h>

uint8_t fb(int a)
{
    return -3;
}

int main()
{
    int a = fb(-3);
    printf("%d",a);
    return 0;
}

代码 2:

#include<stdio.h>

unsigned int fb(int a)
{
    return -3;
}

int main()
{
    int a = fb(-3);
    printf("%d",a);
    return 0;
}

问题是第一个代码按预期返回 253,但第二个代码返回 -3,这是出乎意料的,因为返回类型是无符号的。请帮助我这是怎么可能的?

我用过mingw gcc编译器。

【问题讨论】:

  • 答案是否应该假设“mingw gcc”是唯一的平台?

标签: c types implicit-conversion


【解决方案1】:

在第一个程序中,

  1. 当函数返回时,int -3 (FFFFFFFD) 被强制转换为 uint8_t 是 253 (FD)。高阶字节被丢弃以使其适合。
  2. 执行分配时,uint8_t253 (FD) 通过符号扩展为 253 (000000FD) 转换为 int

在第二个程序中,

  1. 当函数返回时,int -3 (FFFFFFFD) 转换为 unsigned int 4294967293 (FFFFFFFD)。无需丢弃任何字节。
  2. 执行分配时,unsigned int 4294967293 (FFFFFFFD) 转换为 int 为 -3 (FFFFFFFD)。

注意事项:

  • 假设是 32 位整数,但 64 位整数的情况类似。
  • 这是对您发生的事情的解释;这不一定是 C 规范所要求的。

【讨论】:

  • 我无法理解你的意思。你能否用更多的例子来详细说明它。真的会感激大家吗?
  • 没有提及规则、例外、其他平台、解释等等?
  • 转换规则是不同的,尽管做出了正确的假设,包括定义超出范围的转换以适当地签名,但这可能会发生。仍然没有提及规则或您的所有假设(OP 从未说过他只想要 x86 win-32bit 和/或 win-64bit)。
【解决方案2】:

从有符号到无符号的转换将遵循draft C99 standard6.3.1.3 部分中规定的规则有符号和无符号整数,其中说:

否则,如果新类型是无符号的,则值转换为 反复加或减一大于最大值 可以用新类型表示,直到值在 新类型。49)

所以这意味着 -3 将通过将 UMAX +1 添加到值来转换为。对于uint8_t,这是一个相对较小的值253,它适合singed int,因此可以毫无问题地转换为signed int

在您的第二种情况下,返回值为 unsigned int,我们将在转换后得到一个相当大的值,实际上是 std::numeric_limits&lt;unsigned int&gt;::max() + 1 - 3。这不适合 signed int 这是溢出,因此根据 6.5 段落 5 部分的未定义行为:

如果在评估过程中出现异常情况 表达式(也就是说,如果结果不是数学定义的,或者 不在其类型的可表示值范围内),行为 未定义。

【讨论】:

  • 非常感谢 :) 愿上帝保佑你。
  • 等待更多回复。 :)
【解决方案3】:

unsigned int 应打印为%u 而不是%d

【讨论】:

  • 没有unsigned 变量可以打印。
  • 它在问题中声明“返回类型是无符号的”,它在代码中,但是当你打印 %d 时,实际类型是什么并不重要,它会打印一个有符号的int 所以要打印一个你需要的无符号值%u
  • 返回类型是无符号的,然后分配给一个有符号的变量。
  • @Deduplicator,您的回答非常好和正确。但是,当您希望打印 int 时,变量声明为 int 还是 unsigned int 并不重要。系统将仅分配相同的 32 位(或 64 位,具体取决于系统),然后当您请求打印时,它将查看 %d%u 并以这种方式显示这 32 位。我的回答将修复显示中的所谓“错误”,而不是变量本身的值。
  • Re“问题中说“返回类型是无符号的”,但他没有打印返回值。重新“但是,当您希望打印一个 int 时,变量声明为 int 还是 unsigned int 并不重要”,这是一个糟糕的建议。如果他想将其打印为 unsigned int,那么他首先不应该将其分配给 int。
【解决方案4】:

从整数类型转换为无符号整数类型的规则很简单:
根据需要经常加/减(目标类型的最大值 + 1)。

从整数类型转换为有符号整数类型的规则更简单:
保留该值,如果超出范围,则转换未定义。
大多数现代实现(都在 Windows 平台上)将其定义为添加/减去与对应的 unsigned 类型相同的常量,直到它适合为止。

使用这些规则,在第一个示例中从fb() 返回的转换是保值的并且可以:
-3 -> 256-3 = 253 -> 253

第二个示例中的返回超出范围,因此是未定义的行为,但通常情况下:
-3 -> 2CHAR_BIT*sizeof(int)-3 -> -3

奖励事实:

  • 允许向可变参数函数传递有符号/无符号类型,但原始值无法转换,只能假定为指定类型。
  • CHAR_BIT 是一个预处理器常量,给出一个字节中的位数。
  • sizeof 是一个运算符,用于给出类型/变量中的字节数。

【讨论】:

  • 无法获取 2**(CHAR_BIT*sizeof(int)) 语句?请帮助我是初学者?
  • 添加了您要求的那些常量的定义。
  • 非常感谢 :) 愿上帝保佑你。如果你能解释得更多,那对我和其他人也会有很大帮助。
猜你喜欢
  • 2018-08-14
  • 2013-12-19
  • 2014-10-16
  • 2017-09-14
  • 2011-08-24
  • 2017-05-15
  • 2014-05-25
  • 2011-11-25
  • 2010-12-06
相关资源
最近更新 更多