【问题标题】:Program not recognizing the variable as long int nor as unsigned int程序无法将变量识别为 long int 或 unsigned int
【发布时间】:2015-08-13 21:52:33
【问题描述】:

由于有符号整数溢出,我得到的是“-2147483648”,而不是数字“2147483648”。我尝试将变量声明为 long int 和 unsigned int 都没有用。他们只是不被认为是这样的类型。如果有人想知道,我会改变值。

int multiplier = 1,i;
long int mpy = 0;
for(i=32;i>=0;i--){
mpy = 1 << multiplier++;
printf("mpy = %d\n",mpy);
}

【问题讨论】:

  • 请提供一个完整、最小且可验证的示例。
  • 我做了丹尼尔,虽然你只需要循环它直到它作为有符号整数溢出
  • 有符号类型的溢出会导致未定义的行为。你不知道会发生什么。您可以试验并找出通常发生的情况,但不能保证通常发生的事情总是会发生,也不能保证其他编译器或其他版本的编译器会以同样的方式做事。
  • 在您的printf() 格式字符串中使用%d 将打印一个无符号整数,就好像它是一个设置了相同位的有符号整数......同样,使用%u 将显示有符号整数或无符号整数作为无符号。
  • 谢谢你的提示,我不是一个 C 人,我来自 OOP 环境,所以那些 printf 标签对我来说是新奇的,我第一次见到 %u,现在我只有少数人有经验。

标签: c integer overflow long-integer unsigned-integer


【解决方案1】:

由于常量1 是一个int,当左移时,它仍然是一个int。如果你想要一个unsigned long long,那就写成这样:

unsigned long long mpy = 1ULL << multiplier++;

您可以使用longunsigned longlong long 的后缀之一LULLL 代替(以及这些的小写版本,但后缀最好写成大写以避免混淆l1)。选择取决于您真正想要做什么。

注意&lt;&lt; 的结果类型是左侧操作数的类型。移位的结果仅随后转换为赋值运算符左侧的类型。赋值的 LHS 不影响 RHS 上的值的计算方式。

正如user3528438comment 中指出的那样,并且我假设(可能是错误地)你会知道——如果multiplier&lt;&lt; 运算符的 RHS)计算为负值或等于大于或等于整数类型的位数,则调用未定义的行为。

请注意,long longunsigned long long 在 15 年前的旧标准 (C99) 和较新的 C11 标准中是标准的,但它们不是 25 年前 C89/C90 标准的一部分。如果你被困在一个编译器处于时间扭曲的平台上——发布日期在 201x 十年,C 标准兼容日期是 1990 年——那么你必须使用替代平台特定的 64 位技术。更新后的问题中的循环涵盖了 33 个值,因为您从 32 向下计数,包括 0。没有 32 位类型对于 33 个移位中的每个移位都有不同的值。

(高级用户可能对INT35-C Use correct integer precisionsN1899 — Integer precision bits update 感兴趣;对于大多数人来说,它们还有些深奥。我不确定我是否有必要担心所提出的问题。 )

还要注意下面 cmets 中关于 printf() 格式的讨论。您应该确保以正确的格式打印值。对于long int,应该是%ld;对于unsigned long long,那就是%llu。其他类型需要其他格式。确保您使用的是合理的编译器警告选项。如果您使用 GCC,则应该将 gcc -Wall -Wextra -Werror -std=c11 视为一组相当有效的选项;我使用的选项甚至比编译 C 代码时的选项更严格。

【讨论】:

  • 同样重要的是要注意1&lt;&lt;32 是大多数实现的UB,其中1int 并且int 小于或等于32 位。
  • 虽然看起来很合理的解决方案,但不幸的是它对我没有用:(
  • @Maxitj:运气不好。我想这意味着你被微软编译器困住了。值得这么说,因为除非您另有说明,否则人们认为您使用的或多或少的现代编译器支持或多或少的现代标准。
  • 也许这会对这个问题有所启发:ideone.com/sMUFZv 如果您想要并发现它有帮助,可以将其包含在答案中。
  • @user3528438:嗯,是的——%d 格式仅适用于int,而不是所示的long int(严格来说,不适用于unsigned intunsigned long)。当sizeof(int) == sizeof(long) 时,您可以逃脱蓝色谋杀(格式说明符不匹配),在打印单值和小端平台(英特尔)时更是如此。由于mpy 被标记为long int,因此不清楚问题是否在查看unsigned int。但是打印数据的格式也是一个问题。
【解决方案2】:

根据您使用的编译器,如果您在 32 位和 64 位模式下进行编译,您所看到的可能与预期完全一样。

https://software.intel.com/en-us/articles/size-of-long-integer-type-on-different-architecture-and-os

tl;dr:使用 MSVC,intlong 都是 32 位的,如果你想存储更大的数字,你需要升级到 __int64。使用 32 位模式的 gcc 或其他编译器,您会遇到 int = long = 32 位的相同问题,这对您的情况没有帮助。只有当您在非 Microsoft 编译器上转向 64 位编译时,intlong 才会开始分歧。

编辑每个 cmets 部分: int64_tlong long 也是可以使用的符合标准的类型。或者,unsigned 将允许发布者将其值放入 32 位。

【讨论】:

  • 请注意,__int64 特定于 Microsoft 编译器(以及与 MS 代码兼容的编译器)。它没有以任何其他方式标准化。
  • 恕我直言,你错了。无符号整数应该是从 0 到 4294967295 的 32 位。我仍在 32 位的边界内工作。还有一件事,是的,正如上面提到的那样,那么 long long 会发生什么:)
  • Maxitj,原发帖人的代码中没有“未签名”。你是对的,如果原始代码可以修改为无符号,那么 32 位就足够了,但是按照写的,它不起作用。
  • @Maxitj 因为您在printf 中的%d 打印错误。使用%u 正确打印unsigned int。并将1&lt;&lt;multiplier++; 更改为1u&lt;&lt;multiplier++ 以避免溢出UB。
猜你喜欢
  • 2017-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 2016-07-29
  • 2012-01-27
相关资源
最近更新 更多