我们的练习代码输出了意外的-1,我们不知道为什么

时间:2019-11-04 10:58:15

标签: c

因此,我们正在为Uni进行练习,我们无法弄清楚为什么此代码将第二个值输出为-1 我们认为这是由于16位限制所致,但由于我们不知道其实际含义,因此无法确切了解原因,也无法找到有关此问题的任何资料。对不起,如果这看起来真的很愚蠢,请帮助D:

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

int main() {
  int16_t y = 1024, z = 65; // auch "short" als Datentyp verwendbar

  y = y * z;
  printf("1. Ausgabe: %d\n", y);
  printf("2. Ausgabe: %d\n", y / 3 * 3 - 3 * y / 3);
  printf("\n");

  return 0;
}

我们期望2的结果为0,但输出-1

3 个答案:

答案 0 :(得分:1)

int16_t的范围是−32,768 ... 32,767

y * z = 1024 * 65 = 66560 ,因此将存储为 66560%2 ^ 16 = 1024 因此您仍然有 y = 1024 ,而您的语句 y = y * z 是没用的

y / 3 * 3 =(y / 3)* 3 = 341 * 3 = 1023!= y 因为四舍五入

3 * y / 3 =(3 * y)/ 3 = y ,因为没有取整

减去后得到-1

问题是您正在溢出变量并进行整数除法

使用浮点数代替int16_t

答案 1 :(得分:0)

int16_t的范围为[−32768, +32767]-您在第一次乘法时立即溢出了该范围。

第一个printf打印什么?那应该是一个指示。您还会在问题中提及它。

Google int16_t range,它将为您显示上述范围。尝试使用int32_t,看看有什么区别。

答案 2 :(得分:0)

给出y = y * z;,其中所有操作数的类型均为int16_t,其值为1024 * 65 = 66560, 那么有两种可能性:

  • 如果您的系统是8位或16位,则将具有16位int类型。由于操作数已经是16位,并且将出现带符号的整数溢出,从而调用未定义的行为,因此不会进行类型提升。由于16位带符号整数只能存储最多32767个值。
  • 如果您的系统是32位,则yz都将隐式提升(请参阅Implicit type promotion rules)以键入int,然后是32位。乘法的结果为int类型。值66560非常合适。

    然后在分配后将此32位int转换为int16_t。该值将不再适合-发生的是实现定义的从有符号32到有符号16的转换。(理论上,您的系统可能会在此处发出信号。)

    在实践中,大多数系统只会占用66560 = 10400h并截断MS字节,剩下1024 = 400h。

在任何一种情况下,给定输入值的大小,方程y = y * z;都是非常可疑的!这被认为是一个错误。您应该改用uint16_tint32_t


对于y / 3 * 3 - 3 * y / 3,它将是1024 / 3 * 3 - 3 * 1024 / 3。所有操作数都是整数,并且乘法算子*/的算子关联度是从左到右。

因此您得到341 * 3 - 3072 / 3-> 1023 - 1024 = -1


作为旁注,您使用了错误的printf转换说明符。 int16_t最正确的是:

#include <inttypes.h>

printf("1. Ausgabe: %"PRIi16 "\n", y);