【问题标题】:Get warning in debug mode but not in release mode (do I get undefined behavior?)在调试模式下得到警告,但在发布模式下没有(我会得到未定义的行为吗?)
【发布时间】:2015-06-17 12:02:36
【问题描述】:

我的情况有点奇怪。我正在一些设备上编译。 如果我在发布模式下编译,例如

makeCore projectname release exe

一切都很好。如果我在调试模式下编译:

makeCore projectname debug exe

我收到以下警告:

src/administration.c: In function 'SetIp':
src/administration.c:1409: warning: implicit declaration of function 'InputIp'

问:这是否意味着在发布模式下使用我的应用程序是安全的?

为什么会出现这种行为?该怎么办?我正在使用以发布模式编译的二进制文件,我应该担心吗?

编辑:我应该先检查一下这个编译器符合哪个 C 标准,如果它是 C89 之前的,那么我不应该担心,因为它不是未定义的行为吗?

Edit2:我的最终问题是我是否触发了未定义的行为以及如何检查我是否触发了未定义的行为?我不确定我的编译器是否实现了 C89 或 C90 等。也许我应该问供应商这是否是我上面所做的未定义行为?

更新:

这是函数签名:

s32 InputIp(s32 line, u8 * text, s32 otherline, u8 *IP, u8 coordx, s32 coordy);

它是这样称呼的:

s32 res = InputIp(someconstant, u8pointer, otherconstant, otheru8pointer, integer1, integer2);

最后一个问题:由于我首先收到此警告,我可以确定我使用的是使用 C89 的编译器吗?否则会报错?我说的对吗?

【问题讨论】:

  • C 中的 Release mode 和 debug mode 到底是什么? [提示:您缺少标签]
  • 也许编译器警告仅在调试模式下打开。检查您的构建设置!
  • @KlasLindbäck:请查看我更新的问题
  • 您应该考虑的唯一行动方案是调查 为什么 InputIp 未在调试版本中声明(和/或为什么未在发布版本中调用它)然后在找到问题后解决问题。
  • @MattMcNabb:这对我来说并不容易检查它是一个我不知道的复杂 makefile;修复没问题,但我认为这个软件已经写到很多设备上

标签: c


【解决方案1】:

有几个可能的原因导致您有所不同。

  1. 发布版本中的编译器警告级别较低。

这是最可能的原因。

  1. 条件代码。

可能是这样的原因:

`#ifndef DEBUG`

`#include "ip.h"`

`#endif`

请注意,implicit declaration 是您应该认真对待的警告,因为它可以隐藏错误。我建议您在需要时添加前向声明。

【讨论】:

  • 所以你甚至说它可能在发布模式下可能包含该文件 - 我加倍更可能警告被禁用
  • 您应该添加一个前向声明。如果该函数仅在该文件中使用,请在 .c 文件的早期添加它,或重新排序函数以便调用位于定义之后。否则,您应该在声明它的位置包含.h 文件。
  • 我知道如何修复警告!我很感兴趣修复警告是否必要?!我记得在 C89 中我错了没关系?
  • 只要在函数调用中提供正确的参数,它就不会调用未定义的行为,在 c89 中是可以的。如果您提供不正确的参数,您将调用未定义的行为,并且您不会收到关于它的额外编译器警告。
  • 请查看我的更新,我已添加签名以及如何使用它。因此,如果我正确调用它,我可以询问供应商编译器是否使用 C89,如果编译器确实使用 C89,则安全起见?
【解决方案2】:

你不应该依赖implicit declarations,但是如果InputIp被定义为int InputIp();你应该没问题。

【讨论】:

    【解决方案3】:

    在C89中,如果函数的原型是这样的(并且这个原型在函数体的点是可见的,或者函数体使用了相同的原型):

    s32 InputIp(s32 line, u8 * text, s32 otherline, u8 *IP, u8 coordx, s32 coordy);
    

    假设 u8 是 8 位类型,那么在范围内没有原型的情况下调用此函数会导致未定义的行为。

    这种情况下的规则(在范围内调用没有原型的原型函数)是所有参数和返回值在默认参数提升下必须保持不变。 Link to related thread

    这些提升与应用于可变参数函数中匹配... 的参数的提升相同,是:

    • 任何等级低于int 的整数类型都将提升为int
    • float 升级为 double
    • 所有其他类型保持不变

    因此,u8 将通过默认参数提升更改为 int。

    在 C99 中,在范围内调用没有声明的函数是不正确的。


    我强烈建议修复代码,以便使用范围内的原型调用函数。

    【讨论】:

    • 有人告诉我,我还可以通过将其包含在我已经包含的头文件之一中来解决该问题:extern s32 InputIp(s32 line, u8 * text, s32 otherline, u8 *IP, u8 coordx, s32 coordy);?你认为这足以解决问题吗?谢谢。
    • @user70012 只要它与实际的函数体完全匹配,就可以解决它。然而,这是一种糟糕的编码方式;应该发生的是,带有函数体的文件和给出错误的文件都包含与该行相同的标题。 (extern 是多余的,函数定义默认为 extern)
    • “只要它与实际的函数体完全匹配,就可以解决它” 你是什么意思?我在上面对您发表评论的功能签名和我在问题中提到的功能签名不一样吗?谢谢
    • @user70012 是的,我说过,以防您出现转录错误或其他问题。如果你确实犯了一个小错误,那么你只会得到未定义的行为,没有在运行时难以调试的警告。
    • 你的意思是我在变量名中打错字了?我觉得应该没关系吧?但是类型,也许?必须付出更多努力才能拥有检测 UB IMO 的工具
    【解决方案4】:

    尽量提供准时的答案:

    1. Does this mean in the release mode it is safe to use my application:警告意味着编译器找不到InputIp函数原型。预计两种二进制风格之间的应用程序的运行时行为(由此警告引起)没有差异。您应该按照3 的建议进行修复。

    2. Why is this behaviour: 编译器标志好像是根据你传递给make ...的参数在Makefile中调整的

    3. What to do?:为InputIp 添加缺少的函数原型并重建您的应用程序。

    4. I am using the binary compiled in release mode, should I be worried?:在调试模式下编译的应用程序和在发布模式下编译的应用程序之间不应存在由您的问题触发的运行时差异。你应该听从3的建议

    5. Should I maybe first check out which C standard this compiler conforms to:C89/C90 标准与您的问题无关。

    【讨论】:

    • 我对 make 文件和标志非常不满意 - 我正在使用现有的 make 文件
    • 问题略有变化;答案并没有像现在这样解决它
    • 未能找到原型是一个真正的问题。如果未找到原型,则编译器假定返回int 的函数声明,并且仅允许使用某些少数类型的参数。如果实际的函数体与这个假设不匹配,那么它会导致未定义的行为。无论如何,这将是一个容易调查的问题,因此没有理由忽视警告。
    • @MattMcNabb:这就是我的观点,在所有版本的 C 中它都是未定义的行为吗? (可能是我的编译器实现了 C89 - 那么我是安全的?)我应该如何弄清楚,问供应商?
    • @user70012 解决问题所花费的时间比确切地想知道它是否是 UB 花费的时间更少
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多