关于在char变量中存储无符号char值时的类型安全

关于在char变量中存储无符号char值时的类型安全,c,casting,type-conversion,language-lawyer,type-safety,C,Casting,Type Conversion,Language Lawyer,Type Safety,我有一个包含几个字符的char数组。我想将其中一个字符与无符号字符变量进行比较。例如: char myarr = { 20, 14, 5, 6, 42 }; const unsigned char foobar = 133; myarr[2] = foobar; if(myarr[2] == foobar){ printf("You win a shmoo!\n"); } signed char foo = -1; unsigned char bar = 255; if(foo

我有一个包含几个字符的
char
数组。我想将其中一个字符与
无符号字符
变量进行比较。例如:

char myarr = { 20, 14, 5, 6, 42 };
const unsigned char foobar = 133;

myarr[2] = foobar;

if(myarr[2] == foobar){
    printf("You win a shmoo!\n");
}
signed char foo = -1;
unsigned char bar = 255;

if(foo == bar){
    printf("same\n");
}
这种比较类型安全吗

我从C99标准中知道
char
signed char
unsigned char
是三种不同的类型(第6.2.5节第14段)

  • 尽管如此,我是否可以安全地在
    无符号字符
    字符
    之间进行转换,然后再转换回来,而不会丢失精度,也不会出现未定义(或实现定义)的行为

在第6.2.5节第15段中:

实现应将字符定义为具有相同的范围, 表示和行为为
有符号字符
无符号字符

在第6.3.1.3节第3段中:

否则,新类型已签名,且无法在其中表示值;要么结果是实现定义的,要么引发实现定义的信号

我担心如果
char
被定义为
signed char
,那么
myarr[2]=foobar
可能会导致实现定义的值无法正确转换回原始
unsigned char
值;例如,一个实现可能总是导致值
42
,而不考虑所涉及的
无符号

  • 这是否意味着将
    无符号
    值存储在同一类型的
    有符号
    变量中是不安全的
还有什么是实现定义的信号;这是否意味着在这种情况下,实现可以简单地结束程序


在第6.3.1.1节第1段中:

--
long-long-int
的等级应大于
long-int
的等级,后者应大于
int
的等级,后者应大于
short-int
的等级,其等级应大于签名字符的等级

--任何无符号整数类型的秩应等于相应整数类型的秩 有符号整数类型(如果有)

在第6.2.5节第8段中:

对于具有相同符号性和不同整数转换秩的任意两个整数类型 (见6.3.1.1),整数转换秩较小的类型的值范围为a 其他类型的值的子范围

在第6.3.1节第2段中:

如果
int
可以表示原始类型的所有值,则该值将转换为
int
;否则,它将转换为无符号整数

在第6.3.1.8节第1段中:

否则,两个操作数都将转换为无符号整数类型 对应于带符号整数类型的操作数的类型

char
的范围保证与
signed char
unsigned char
的范围相同,这两个字符都是
int
unsigned int
的子范围,因为它们的整数转换秩较小

由于整数提升规则规定在求值之前,
char
signed char
unsigned char
至少提升为
int
,这是否意味着
char
可以在整个比较过程中保持其“签名性”

例如:

char myarr = { 20, 14, 5, 6, 42 };
const unsigned char foobar = 133;

myarr[2] = foobar;

if(myarr[2] == foobar){
    printf("You win a shmoo!\n");
}
signed char foo = -1;
unsigned char bar = 255;

if(foo == bar){
    printf("same\n");
}
  • 当使用显式的
    (无符号字符)
    强制转换时,
    foo==bar
    是否计算为假值,即使
    -1
    相当于
    255

更新

在第J.3.5节第1段中,关于哪些情况会导致实现定义的值和行为:

--将整数转换为有符号整数类型的结果或所产生的信号 当该值无法在该类型的对象中表示时(6.3.1.3)

  • 这是否意味着即使是显式转换也不安全
例如,以下代码是否会导致实现定义的行为,因为
char
可以定义为有符号整数类型:


“这是否意味着
char
可以在整个比较过程中保持其“符号性”<代码>-1作为
签名字符
将升级为
签名整数
,该整数将保留其
-1
值。至于
无符号字符
,它在升级时也将保留其
255
值,因此是的,比较将为false。如果希望它的计算结果为true,则需要显式强制转换。

我已经测试了您的代码,但它没有将
(有符号字符)-1
(无符号字符)255
进行相同的比较。 您应该首先将有符号字符转换为无符号字符,因为它在操作中不使用MSB符号位


我对使用有符号字符类型进行缓冲区操作的经验不好。像你的问题这样的事情就会发生。然后确保在编译过程中打开了所有警告并尝试修复它们。

这与字符的内存存储方式有关,在无符号字符中,所有8位用于表示字符的值,而有符号字符仅使用7位表示数字,第8位表示符号

例如,让我们取一个更简单的3位值(我将此新值类型称为tinychar):

通过查看此图表,您可以根据位的排列方式看到有符号和无符号tinychar之间的值差异。直到
char foo = -25;
unsigned char bar = foo;

if(foo == bar){
    printf("This line of text will not be printed.\n");
}
/* binary representation prefix: 0b */
(signed char)(-25)   = 0b11100111
(unsigned char)(231) = 0b11100111
unsigned foo = UINT_MAX;
signed bar = foo;    /* possible implementation-defined behavior */
signed char foo = -1;
unsigned char bar = 255;

if((unsigned char)foo == bar){
    printf("same\n");
}