- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我知道这个问题已经被问过无数次,而且似乎已经回答了无数次,但我似乎无法将答案与我自己的经历相匹配。
C 标准规定对于加法“两个操作数都应具有算术类型”(6.5.6.1)。算术类型涵盖整数和浮点类型(6.2.5.18),最后整数类型是 char、short、int、long 和 long long,它们以有符号和无符号类型存在(6.2.5.4 和 6.2.5.6)。根据通常算术转换的规则“如果两个操作数的类型相同,则不需要进一步转换”。到目前为止一切顺利。
据我了解,正如“The C Book”中的示例所示,“[n]o 算术是由 C 以小于 int 的精度完成的”,这是应用积分提升的地方。我在标准中找不到对此的任何引用,但我似乎已经看过很多次了。
既然unsigned char是算术类型,通常的算术转换规则规定相同类型的操作数不需要转换,为什么需要整型提升?
我使用两个不同的编译器对此进行了测试。我写了一个简单的程序来进行字符加法:
unsigned char a = 1;
unsigned char b = 2;
unsigned char c = a + b;
目标平台是使用 8 位架构的 Atmel Mega8 uC。因此,如果操作数应进行整数提升,则整数加法需要使用两个寄存器。
使用 Imagecraft AVR 编译器编译它,没有优化,并启用了严格和 ANSI C 可移植性选项,产生了这个汇编代码:
mov R16, R20
add R16, R18
使用 avr-gcc(我不知道有一个类似于 gcc 的 -strict 的 ANSI 开关):
$ avr-gcc -O0 -mmcu=atmega8 -S -c main.c
生成的程序集:
ldd r25,Y+1
ldd r24,Y+2
add r24,r25
std Y+3,r24
两种情况下的结果代码都对单个字节进行操作。我得到类似的结果和 & 和逻辑 ||和 &&。这是否意味着该标准允许对字符类型进行算术运算而无需整数提升,或者仅仅意味着这些编译器不符合标准?
附加:
事实证明,这完全取决于结果存储的类型。上面显示的示例仅当结果存储在 char 中时才成立,而不取决于加法的结果。将 a 设置为 0xFF 并将 b 设置为 1 会生成完全相同的汇编代码。
如果 c
的类型更改为 unsigned int,则生成的程序集如下所示:
mov R2,R20
clr R3
mov R16,R18
clr R17
add R16,R2
adc R17,R3
即使在结果可以保存在单个字节中的情况下,即 a=1 和 b=2。
最佳答案
C 2011 (n1570) 6.3.1.8(“通常的算术转换”)1 声明整数提升在考虑类型是否相同之前执行::
Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:
If both operands have the same type, then no further conversion is needed…
因此,在 C 抽象机中,unsigned char
值必须在执行算术运算之前提升为 int
。 (对于 unsigned char
和 int
具有相同大小的反常机器有一个异常(exception)。在这种情况下,unsigned char
值被提升为 unsigned int
而不是 int
。这是深奥的,在正常情况下不需要考虑。)
在实际机器中,操作的执行方式必须如同在抽象机器中执行操作时获得相同的结果。因为只有结果才重要,实际的中间操作不需要与抽象机完全匹配。
当将两个 unsigned char
值的总和分配给 unsigned char
对象时,总和将转换为 unsigned char
。这种转换实质上会丢弃超出适合 unsigned char
的位的位。
这意味着 C 实现无论是否这样做都会得到相同的结果:
int
。int
算法添加值。unsigned char
。或者这个:
unsigned char
算法添加值。因为结果相同,C 实现可以使用任何一种方法。
为了比较,我们可以考虑这个语句:int c = a + b;
。此外,假设编译器不知道 a
和 b
的值。在这种情况下,使用 unsigned char
算术进行加法运算可能会产生与将值转换为 int
并使用 int
算术不同的结果。例如,如果 a
是 250 而 b
是 200,那么它们作为 unsigned char
值的总和是 194 (250 + 200 % 256),但是它们在 int
算术中的总和是 450。由于存在差异,C 实现必须使用获得正确总和 450 的指令。
(如果编译器确实知道 a
和 b
的值,或者可以证明总和适合 unsigned char
,那么编译器可以再次使用 unsigned char
算法。)
关于char和通常的算术转换规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12841278/
这个问题在这里已经有了答案: Why don't Java's +=, -=, *=, /= compound assignment operators require casting? (11 个
当我尝试运行以下代码时,List(.of) 无法编译并给出主题错误。 package collections; import java.util.LinkedHashSet; import java.
我正在尝试编译使用 ChatScript 库的程序。这是我在名为 main.cpp 的文件中的代码: #include #include "common.h" using namespace std
我想在我的程序中外部使用 ChatScript。在documents它说: Embedding Step #1 First, you will need to modify `common.h and
假设我有一个 char,我想用一行代码将其 strcat() 转换为 char 数组。对于 [一个非实用的] 示例: strcat("ljsdflusdfg",getchar()); 或者我想做相反的
我有以下类型签名: *Main Lib> let f :: a -> a -> a -> a; f = undefined *Main Lib> let x :: Char; x = undefin
我正在学习如何在 C 中使用指针(使用 malloc 和 free),但我在这个练习中遇到了一些麻烦。我只想制作一个指针数组,我想在其中保存每个单词的方向。然后我想为一个特定的词做一个 free(),
我有一个字符*: char* version = "10.5.108"; 我想通过字符分隔符获取两个新的 char*。 char delimiter = '.'; 执行以下代码后: printf("|
最近在学习Cpp,今天在学习使用Clion做测试的时候,发生了奇怪的事情。 这是我的代码 int main() { char c = 'b'; char carr[1]{'a'};
我对 c 很陌生,我正在审查一些代码。我遇到了这个: static char * fromDataType; static char * toDataType; static char * fromR
我有一个像这样的动态结构: struct network { int count; char** ips; } 如果我知道每个字符串数组都是 16 个字节(即 INET_ADDRSTR
我有一个旧程序,其中使用了一些库函数,但我没有那个库。 所以我正在使用 C++ 库编写该程序。在那个旧代码中有一些函数是这样调用的 *string = newstrdup("这里有一些字符串"); 字
我正在编写一个函数,该函数接受 ArrayList,然后将每个 char[] 复制到另一个增加长度的 char[] 中,然后将新的 char[] 添加到新的 ArrayList 中。当我尝试复制数组时
我正在寻找 map >并生成每个可能的 map从它。 我知道这可能会占用大量内存并需要一些时间。 每个map需要包含每个字母 a-z,并映射到唯一的 a-z 字符。 IE。啊bjcp迪EVfh嘎血红蛋
#define NAME_LEN 20 #include "stdio.h" #include "stdlib.h" #include "string.h" #pragma warning(disab
所以我必须创建一个函数来找到一对带有第一个字母并返回第二个字母的函数。 我实际上找到了一个答案,但是使用 map 功能却找不到。 lookUp :: Char -> [(Char, Cha
我最近接受采访并要求写mystrcat(*s1, *s2, *s3) 其中s1 和s2 是源字符串连接结果由 s3 给出。有人告诉我,不要担心 s3 的内存分配,并假设 s1 和 s2 不是空/无效字
今天我与一位同事讨论了他(对我来说)不寻常的“main”函数签名。他喜欢这样声明: int main(int argc, char* (*argv)[]) { printf("at index
这个问题在这里已经有了答案: 关闭 12 年前。 Possible Duplicate: What's the difference between new char[10] and new cha
通常字符串文字是 const char[] 类型。但是当我把它当作其他类型时,我得到了奇怪的结果。 unsigned char *a = "\355\1\23"; 使用此编译器会抛出警告“初始化中的指
我是一名优秀的程序员,十分优秀!