【问题标题】:Data Type Mismatch and Conflicting Compilers数据类型不匹配和编译器冲突
【发布时间】:2016-03-02 02:31:38
【问题描述】:

我正在一个名为 TutorialsPoint 的网站上学习 C 编程语言的基本概念。本网站上的源代码示例可以包括一个“试用”按钮,该按钮打开一个带有在线 c 编译器(GNU GCC 版本 4.7.2)的在线 c 编程环境。在一个示例中,演示了 sizeof() 函数。这是源代码。

#include <stdio.h>
#include <limits.h>

int main() {

  printf("Storage size for int : %d \n", sizeof(int));

  return 0;
}

课程链接:TutorialsPoint - C Data Types

当该程序在在线编程环境中编译和执行时,会产生以下输出:

"Storage size for int : 4"

当我尝试使用 GNU GCC 5.2.1 版在我的计算机上编译相同的代码时,我收到以下错误消息:

gcc sizeofExample.c
sizeofExample.c: In function 'main':
sizeofExample.c:6:10: warning: format '%d' expects argument of type 'int',
but argument 2 has type 'long unsigned int' [-Wformat=]
  printf("Storage size for int: %d \n", sizeof(int));
         ^

这是我的源代码,只是为了彻底:

#include <stdio.h>
#include <limits.h>

int main()
{
  printf("Storage size for int : %d \n", sizeof(int));

  return 0;
}

我了解此错误是由于 %d [int 数据类型] 和 sizeof(int) [long unsigned int] 之间的数据类型不匹配造成的。

为什么我的编译器检测到数据类型不匹配,而 TutorialsPoint 的在线编译器却没有?

【问题讨论】:

  • 这是一个警告,而不是错误。 Gcc 仍然会为你编译它。它只是超越并让您知道代码可能不正确,即使它可以编译。较小的编译器可能不会执行生成此警告所需的额外分析
  • @PeteBaughman:当然,在这种情况下,较小的编译器只会调用未定义的行为; gcc 超出预期,但按照标准,代码是错误的,并且很容易在大端架构上遇到问题,或者在将其他参数传递给 printf 而并非所有参数都在寄存器中传递的情况下.
  • 我没有意识到 GCC 仍在为我编译这段代码。这条评论回答了我的问题。我一定会注意警告并在 printf() 函数中使用正确的数据类型。
  • 这是错误的,但在运行时方式是错误的,而不是编译时方式。 Gcc 正在执行额外的静态分析,但就符合标准的编译器而言,这是有效的。您在字符串中传递了错误的值,但编译器不必关心。就像除以零一样。类型检查正常,所以编译器不必关心。
  • @Olaf:这是未定义的行为,但编译器无法识别它。从符合标准的编译器的角度来看,它只是一个不透明的 C 风格字符串,后跟可变参数; gcc 特殊情况 printf 因为它相对容易做并且是常见的错误来源,但是符合标准的编译器不需要寻找这样的未定义行为,它是未定义的,因此他们可以尝试使其工作,或者不,或者放火烧你的房子,随他们的选择。

标签: c printf sizeof


【解决方案1】:

sizeof 产生size_t 结果(一个无符号数,在 32 位系统上通常为 4 个字节,在 64 位系统上通常为 8 个字节)。您应该使用适当的printf 格式代码,在本例中为%zuz 表示“宽度相当于size_t”,u 表示“无符号值”)。这应该在所有系统上都能正常工作(除了极少数不支持z 大小修饰符的非常古老的系统)。

在线编译器可能不会抱怨,因为:

  1. 它没有执行深入的printf 格式代码检查gcc 确实 或
  2. 它是一个 32 位编译器,size_tint 大小相同(尽管符号不同),所以那里没有大小不匹配,而您本地的 gcc 是一个 64 位编译器,并且尺寸不同。
  3. 编译器根本不显示警告,以使初学者的输出保持简单。

请注意,gcc 只是警告,而不是错误输出,因此代码将完成编译并运行。不过,通常警告表明存在问题,因此进一步调查是一件好事。

【讨论】:

  • 或者它只是不像大多数在线编译器那样显示警告(这很愚蠢)。
  • @Ben:好点。我不经常使用它们,所以我不知道它们可能有多严格。对于非遗留代码,我总是将警告调高(通常使它们出错),以便在编译时捕捉到这样的废话,以免在运行时让我难以诊断。
  • 我完全同意,也 +1,不知道为什么有人投反对票?
【解决方案2】:

这是一个警告而不是错误,因此编译正在完成并生成一个可执行文件,但 GCC 警告您可能导致不良行为的某些事情。至于为什么 TutorialPoint 没有显示这个警告,类似的在线编译器网站 ideone.com also doesn't throw this warning. 可以看到 here 说 Ideone 使用的是 GCC 编译器。在线网站通常会隐藏警告以简化用户的输出。修复警告总是一个好主意,在这种情况下你会使用:

printf("Storage size for int : %zu \n", sizeof(int));

这可能会为您Undefined Behaviour 避免不匹配的printf 类型读取更多内存的问题。阅读更多关于此here 的信息。

【讨论】:

    【解决方案3】:

    为什么我的编译器检测到数据类型不匹配

    因为printf 期望%zu(而不是%d)对应sizeof(type)

    【讨论】:

    • 为什么在线编译器不期望 sizeof(type) 为 %zu?
    • 我不使用在线编译器,因此无法对此发表评论。如果您使用%d,标准编译器(即 gcc)会给您一个警告:
    猜你喜欢
    • 2021-04-30
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多