每次在c中输出不同?

每次在c中输出不同?,c,printf,format-specifiers,C,Printf,Format Specifiers,我正在努力学习C语言,我已经很困惑了 #include <stdio.h> int main(void) { int a = 50000; float b = 'a'; printf("b = %f\n", 'a'); printf("a = %f\n", a); return 0; } #包括 内部主(空) { INTA=50000; 浮动b='a'; printf(“b=%f\n”,“a”); printf(“a=%f\n”,a); 返

我正在努力学习C语言,我已经很困惑了

#include <stdio.h>

int main(void)
{
    int a = 50000;
    float b = 'a';
    printf("b = %f\n", 'a');
    printf("a = %f\n", a);
    return 0;
}
#包括
内部主(空)
{
INTA=50000;
浮动b='a';
printf(“b=%f\n”,“a”);
printf(“a=%f\n”,a);
返回0;
}

上述代码每次使用
gcc
生成不同的输出。为什么?

指定符
%f
需要与浮点参数(
float
double
)匹配,而不是给它
int
s。不匹配类型是未定义的行为,这意味着它可以做任何事情,包括每次打印不同的结果

希望这有帮助,祝你好运:)


编辑:感谢chqrlie的澄清

不可预测的行为

当您尝试使用不匹配的格式说明符打印值时,编译器会给出不可预测的输出。使用
%f
作为
字符
整数
的格式说明符的行为未定义

根据数据类型在程序中使用正确的格式说明符:

printf("%d\n", 'a'); // print ASCII value
printf("%d\n", a);

您为
%f
格式传递一个
int
值('a'),该格式应为
float
double
。这是未定义的行为,可能导致同一程序的每次执行都有不同的输出。第二个
printf
有相同的问题:
%f
需要一个
float
double
,但您传递了一个
int

以下是更正的版本:

#include <stdio.h>

int main(void) {
    int a = 50000;
    float b = 'a';

    printf("a = %d\n", a);
    printf("b = %f\n", b);
    printf("'a' = %d\n", 'a');

    return 0;
}
在启用更多警告的情况下编译,使用命令行参数
-Wall-W-Wextra
可以让编译器执行更多的一致性检查并抱怨潜在的编程错误。它会在发布的代码中检测到错误

事实上,
clang
仍然抱怨上述更正:

clang -O2 -std=c11 -Weverything fmt.c -o fmt
fmt.c:8:24: warning: implicit conversion increases floating-point precision: 'float' to 'double' [-Wdouble-promotion]
    printf("b = %f\n", b);
    ~~~~~~             ^
1 warning generated.
b
在传递到
printf()时升级为
double
double
类型比
float
类型具有更高的精度,如果请求的小数比原始类型多,则可能会输出误导性的值


建议始终使用
double
进行浮点计算,并将
float
类型保留为更适合的特定情况,例如计算机图形API、某些二进制交换格式…

首先,gcc应针对上述代码发出警告。这是因为格式说明符不匹配

不匹配的格式(
printf()
以及
scanf()
)将在C中产生不可预测的行为。尽管gcc希望隐式地处理可能的类型转换,如
int
float

这里有两个很好的参考资料。

以下内容将按预期工作

#include <stdio.h>

int main(void)
{
    int a = 50000;
    float b = 'a';
    printf("b = %f\n", (float)'a');
    printf("a = %f\n", (float)a);
    return 0;
}
#包括
内部主(空)
{
INTA=50000;
浮动b='a';
printf(“b=%f\n”,(float)“a”);
printf(“a=%f\n”,(float)a);
返回0;
}

从实现的角度来看,将浮点数(即
%f
所期望的)作为变量参数列表(即
..
printf
原型中的含义)和整数(即
'a'
是什么,特别是
int
类型)传递可能会使用不同的寄存器和内存布局

这通常由ABI调用约定定义。具体来说,在x86_64中,
%xmm0
将由printf读取(使用单位化值),但gcc将在
printf
调用中填充
%rdi

详见第页。56


您应该注意到,C是一种非常低级的语言,它在实现过程中会遇到很多令人困惑的情况(包括整数溢出和下溢、单位化变量、缓冲区溢出)。这允许获得最大的性能(通过避免大量的检查),但会留下诸如此错误之类的错误

您面临的主要困难是所使用的数据类型。 当您创建一个变量时,您告诉内存必须保留的大小才能正常工作。像
char
一样,大小为1字节,
int
等于4字节,
float
32字节。使用相同的数据类型以避免产生不可预测的结果是很重要的

char a = 'a';
printf("%c",a);

int b = 50000;
printf("%d",b);

float c = 5.7;
printf("%f", c);

有关详细信息:

在第一条
printf
语句中,您尝试将
char
打印为
float
。这可能是部分原因。使用不匹配的格式和参数类型是未定义的行为。请认真对待编译器的警告。您应该了解格式说明符。是否要执行浮点b='a'?而且不仅仅是=一个?
%f
实际上需要一个
浮点
参数<当传递到
printf
(和任何其他可变函数)时,code>float
参数将升级为
double
'a'
在C中不是
char
,而是
int
值。顺便说一句,
char
值在传递到
printf
时会隐式提升为
int
char a = 'a';
printf("%c",a);

int b = 50000;
printf("%d",b);

float c = 5.7;
printf("%f", c);