【问题标题】:How to make gcc/g++ warn on comparing signed and unsigned char如何使 gcc/g++ 在比较有符号和无符号字符时发出警告
【发布时间】:2013-11-14 11:12:16
【问题描述】:

我有以下代码:

#include <stdlib.h>
#include <stdio.h>

void test(unsigned char * arg) { }

int main() {
    char *pc = (char *) malloc(1);
    unsigned char *pcu = (unsigned char *) malloc(1);

    *pcu = *pc = -1;                                        /* line 10 */

    if (*pc == *pcu) puts("equal"); else puts("not equal"); /* line 12 */

    pcu = pc;                                               /* line 14 */

    if (pcu == pc) {                                        /* line 16 */

        test(pc);                                           /* line 18 */

    }
    return 0;
}

如果我用 gcc 版本 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) 编译它(但不限于这个特定版本)和选项

gcc a.c -pedantic -Wall -Wextra -Wsign-conversion -Wno-unused-parameter; ./a.out

我收到以下警告

test.c: In function ‘main’:
test.c:10:21: warning: conversion to ‘unsigned char’ from ‘char’ may change the sign of the result [-Wsign-conversion]
test.c:14:13: warning: pointer targets in assignment differ in signedness [-Wpointer-sign]
test.c:16:17: warning: comparison of distinct pointer types lacks a cast [enabled by default]
test.c:18:17: warning: pointer targets in passing argument 1 of ‘test’ differ in signedness [-Wpointer-sign]
test.c:4:6: note: expected ‘unsigned char *’ but argument is of type ‘char *’
not equal

g++ 警告/错误类似。我希望我能理解为什么第 12 行的比较被评估为 false,但是在这种情况下有没有办法得到警告?如果不是,第 12 行和引起警告的行之间是否存在一些主要区别? char 和 unsigned char 的比较不应该得到警告有什么具体原因吗?因为至少乍一看,第 12 行在我看来比例如更“危险”。第 16 行。

一个简短的“背后故事”:我必须将来自不同来源的代码片段组合在一起。其中一些使用 char,一些使用 unsigned char。 -funsigned-char 可以正常工作,但我不得不避免它,而是添加正确的类型转换。这就是为什么这样的警告对我有用的原因,因为现在,如果我忘记在这种情况下添加类型转换,程序就会默默地失败。

提前致谢,P。

【问题讨论】:

  • 有趣的是,如果我将chars 更改为ints,它确实会发出警告。
  • @ams:我想区别在于chars 的情况下charunsigned char 都转换为(signed)int。那么值是-1255,它们有相同的类型(所以当时没有任何警告的理由),当然它们不相等。
  • 是的,我刚刚写下了那个答案。 :)

标签: gcc


【解决方案1】:

我相信这是由整数提升造成的。

当您处理charshort 时,C 实际所做的(这是由标准定义的,而不是实现)是在执行任何操作之前将这些类型提升为int。我认为,理论是int 应该是底层机器使用的自然大小,因此是最快、最有效的大小;事实上,大多数架构会在加载字节时进行这种转换,而不会被询问。

由于signed charunsigned char 都可以很好地适应signed int 的范围,因此编译器对两者都使用它,并且比较变成了纯符号比较

如果表达式左侧的类型不匹配(第 10 行和第 14 行),则需要将其转换回较小的类型,但它不能,因此会收到警告。

当您比较不匹配的指针(第 16 行)并传递不匹配的指针(第 18 行)时,整数提升不起作用,因为您实际上从未取消引用指针,因此从未比较整数(char 是当然也是整数类型)。

【讨论】:

  • 谢谢,但我不确定我是否明白这一点。我希望我确实(不知何故 :-) 了解所有这些事情是如何工作的,但我想说的是,在我看来,比较 char 和 unsigned char 似乎比其他一些产生警告的情况更危险,即第 16 行或例如第 16 行。未使用函数参数的警告(在我的场景中已关闭)。这就是为什么我很好奇为什么这样的比较不会产生警告。
  • 重点是比较有符号和无符号字符是安全的,只要您实际上并不期望(-1 == 255) == true。那里没有未定义的行为。
  • 我希望声明但未使用的参数和变量也是安全的,并且警告存在。所以不同的是,在除第 12 行之外的所有其他情况下,标准并不严格,IOW 结果不是由标准定义,而是由特定的编译器实现定义 --- 并且 gcc 警告实际上并不意味着“嘿,这很奇怪,你确定吗?”,但他们只警告我结果取决于编译器吗?我一直认为前者是对的,但可能我错了。 :-)
  • 一些警告可以帮助你发现写一半的代码(你写了一个变量,但后来忘记使用它,或者你删除了一个变量但错过了声明)。有些是为了引导你绕过陷阱。有些是因为您的代码违反了标准中的约束,但编译器是允许的。
猜你喜欢
  • 1970-01-01
  • 2014-01-28
  • 1970-01-01
  • 2013-11-11
  • 2011-04-09
  • 2021-10-31
  • 2011-07-21
  • 1970-01-01
相关资源
最近更新 更多