有没有办法在整数提升时得到警告?

问题描述 投票:0回答:3

例如:

在这种情况下,我想有一个编译器警告。

这可能吗?

#include <stdio.h>

int main(void)
{
    char i;
    int count = 555;
    
    for(i = 0; i < count; i++)
        printf("%d\n", i);
    
    return 0;
}
c gcc gcc-warning
3个回答
0
投票

因为这里的核心问题是整数溢出/赋值超出范围。如果

char
已签名,则它是运行时实现定义或未定义的行为,而不是真正的编译器业务。最终(不幸的是)C 程序员有责任了解和发现代码中所有形式的定义不当的行为。

编译器的诊断能力也往往很差,他们的工作是检查您的代码是否有效 C,如果不是则通知您。如果你幸运的话,他们可能还会提醒你常见的错误和未定义的行为,但这不是你可以指望的,它只是一个奖励。

关于隐式提升,在 gcc 中有

-Wconversion
但这个选项非常不稳定且不可靠。它不会在您的情况下发出警告,而在其他情况下会发出错误警告。

最好的选择是使用称为“静态分析器”的外部工具。它们类似于编译器,但专注于查找有问题的代码和错误。有一些开源工具,如 clang-tidy 和 Frama-C,但大多数此类工具都是商业的。

此类静态分析器的一种形式是“MISRA 检查器”,用于验证是否符合 MISRA C 准则。 MISRA C 的一个重要部分致力于查找隐式提升/意外类型更改错误,因此在这种情况下,我建议获得 MISRA C 静态分析器。


0
投票

有没有办法在整数提升时得到警告?

OP 的担忧是真实的,但在 integer promotion.

上错位了

编译器选项的存在是为了帮助 OP,但它们的出现是有选择性的。


i++
就像
i = i + 1
(但
i
只计算了一次)并且对于 8 位
i
,从
char
int
的提升在添加之前被明确定义。添加定义明确,也在范围内。

int
分配给具有超出范围的值的
char
实际上是 integer demotion 和对 OP 的合理关注。一些编译器提供选项来捕获其中的 some。 “否则,新类型已签名,并且无法在其中表示值;结果是实现定义的,或者引发了实现定义的信号。”适用。

char i;

// warning: conversion from 'int' to 'char' may change value [-Wconversion]
i = rand();

// But not here
i++;
i = i + 1;
i = (int) (i + 1);

对于

printf("%d\n", i);
char i
作为
int
论点的一部分被默默地提升为
...

这里不关心值。


i < count
总是正确的。整数提升不是问题,但
i < count
永远不会是假的。

编译器提供一些选项,如下所示,有时会发出警告代码分析工具 提供额外的警告。

 // warning: comparison is always true due to limited range of data type [-Wtype-limits]
for(i = 0; i <= (char) 127; i = i + 1)
 
// No warning.
for(i = 0; i <= count; i = i + 1)

// No warning.
char b = 127;
for(i = 0; i <= b; i = i + 1)

// No warning and no integer promotion 
int m = INT_MAX;
for(int i = 0; i <= m; i = i + 1)

注意:这里没有符号整数溢出,也没有未定义的行为。有实现定义的行为


-1
投票

您可以使用

clang -Wall -pedantic
获得的唯一警告与代码中的实际问题无关:

<source>:3:9: error: a function declaration without a prototype is deprecated in all versions of C [-Werror,-Wstrict-prototypes]
int main()
        ^
         void

出于某种原因,gcc 和 clang 都没有报告由

i
变量的有限范围引起的无限循环,这很奇怪,因为 他们确实检测到它并利用它

gcc 12.2 -O3
汇编代码:

.LC0:
        .string "%d\n"
main:
        push    rbx
        xor     ebx, ebx
.L2:
        movsx   esi, bl
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        add     ebx, 1
        call    printf
        jmp     .L2

clang 15.0 -O3 assembly code:

main:
        push    rbp
        push    rbx
        push    rax
        lea     rbx, [rip + .L.str]
        xor     ebp, ebp
.LBB0_1:                                # =>This Inner Loop Header: Depth=1
        movsx   ebp, bpl
        mov     rdi, rbx
        mov     esi, ebp
        xor     eax, eax
        call    printf@PLT
        inc     bpl
        jmp     .LBB0_1
.L.str:
        .asciz  "%d\n"

这是疯狂优化的一个简单而有说服力的例子:编译器检测到一个明显无意的无限循环,他们没有向程序员报告这个发现,而是直接生成失控代码。

© www.soinside.com 2019 - 2024. All rights reserved.