我正在尝试将char打印为正值:
char ch = 212;
printf("%u", ch);
Run Code Online (Sandbox Code Playgroud)
但我得到:
4294967252
Run Code Online (Sandbox Code Playgroud)
我如何212进入输出?
根据C标准(6.5.2.2第6段)
如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并将具有float类型的参数提升为double.这些被称为默认参数促销.如果参数的数量不等于参数的数量,则行为未定义.如果函数是使用包含原型的类型定义的,并且原型以省略号(,...)结尾,或者促销后的参数类型与参数类型不兼容,则行为未定义.如果函数是使用不包含原型的类型定义的,并且促销后的参数类型与促销后的参数类型不兼容,则行为未定义,但以下情况除外:
- 一个提升类型是有符号整数类型,另一个提升类型是相应的无符号整数类型,并且该值可在两种类型中表示;
- 这两种类型都是指向字符类型或空格的限定或不合格版本的指针.
因此,一般来说,只要传递的值适合两种类型,传递int到需要unsigned int(或反之亦然)的可变函数是没有错的.但是,printf读取规范(7.19.6.1第9段):
如果转换规范无效,则行为未定义.如果任何参数不是相应转换规范的正确类型,则行为未定义.
签名/未签名不匹配也不例外.
这是否意味着printf("%x", 1)调用未定义的行为?
对于正在开发的软件,我有两种构建方式,一种是针对int大小为16位的嵌入式系统,另一种是针对int大小为32位的台式机进行测试。我使用的是固定宽度的整数类型<stdint.h>,但整数提升规则仍取决于int的大小。
理想情况下,由于整数提升,我希望打印以下代码65281(将整数提升为16位)而不是4294967041(将整数提升为32位),以使其与嵌入式系统上的行为完全匹配。我要确保在台式机测试期间给出一个答案的代码与嵌入式系统上给出的答案完全相同。对于GCC或Clang的解决方案都可以。
#include <stdio.h>
#include <stdint.h>
int main(void){
uint8_t a = 0;
uint8_t b = -1;
printf("%u\n", a - b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编辑:
我给出的示例可能不是最好的示例,但是我确实希望整数提升为16位而不是32位。请看以下示例:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void){
uint16_t a = 0;
uint16_t b = 1;
uint16_t c = a - 2; // "-2": 65534
uint16_t d = (a - b) / (a - c);
printf("%" PRIu16 "\n", d);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是0在32位系统上,这是因为在提升为(signed)int而不是后从整数除法截断了32767。
到目前为止,最好的答案似乎是使用仿真器,这不是我想要的,但是我认为确实是有道理的。从理论上来说,编译器似乎可以生成行为,就像int的大小为16位一样,但是我想实践中没有简单的方法可能并不奇怪,对这种模式和任何必要的运行时支持的需求可能不大。
编辑2: …
我想通过班次unsigned char存入一个char.由于两种数据类型具有相同的长度(我的机器上有1个字节),我希望以下代码可以工作:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int main () {
printf ("%d\n", sizeof(char));
printf ("%d\n", sizeof(unsigned char));
unsigned char test = 49;
char testchar = (char) (test - 127);
printf ("%x\n", testchar);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但事实并非如此.特别是,我得到了以下输出:
1
1
ffffffb2
Run Code Online (Sandbox Code Playgroud)
这表明char已被铸造int.有人有解释,希望是解决方案吗?