【问题标题】:Different output every time in c?每次在c中输出不同?
【发布时间】:2017-06-14 17:33:04
【问题描述】:

我正在努力学习 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;
}

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

【问题讨论】:

  • 在第一个printf 语句中,您尝试将char 打印为float。这可能是部分原因。
  • 使用不匹配的格式和参数类型是未定义的行为
  • 认真对待编译器的警告。
  • 您应该阅读一下格式说明符。
  • 你的意思是做 float b = 'a' 吗?而不仅仅是 = a ?

标签: c printf format-specifiers


【解决方案1】:

不可预测的行为。

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

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

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

【讨论】:

    【解决方案2】:

    %f 说明符需要与浮点参数(floatdouble)匹配,而您将其改为 ints。不匹配类型是未定义的行为,这意味着它可以做任何事情,包括每次打印不同的结果。

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

    编辑:感谢 chqrlie 的澄清!

    【讨论】:

    • %f 实际上需要 floatdouble 参数。 float 参数在传递给 printf(和任何其他可变参数函数)时提升为 double'a' 不是 C 中的 char,它是 int 值。顺便说一句,当传递给printf 时,char 值将隐式提升为 int
    【解决方案3】:

    您遇到的主要困难是您使用的数据类型。 创建变量时,您是在告诉内存必须保留的大小才能正常工作。就像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);
    

    欲了解更多信息:C-Variables

    【讨论】:

      【解决方案4】:

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

      这通常由 ABI 调用约定定义。具体来说,在 x86_64 中,%xmm0 将被 printf 读取(具有未初始化的值),但 gcc 将在 printf 调用中填充 %rdi

      System V Application Binary Interface AMD64 Architecture Processor Supplement, p. 中查看更多信息。 56

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

      【讨论】:

        【解决方案5】:

        您将int 值('a')传递给%f 格式,期望floatdouble。这是未定义的行为,可能会导致同一程序的每次执行都产生不同的输出。第二个 printf 也有同样的问题:%f 期望 floatdouble 但你传递了 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;
        }
        

        输出:

        a = 50000
        b = 97.000000
        'a' = 97
        

        在启用更多警告的情况下进行编译,使用命令行参数-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() 时提升为 doubledouble 类型比 float 类型具有更高的精度,如果请求的小数比提供的原始类型多,则可能会输出误导值。

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

        【讨论】:

          【解决方案6】:

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

          不匹配的格式(printf()scanf())会在 C 中产生不可预测的行为。尽管 gcc 预计会隐式处理可能的类型转换,例如 intfloat

          这里有两个不错的参考。
          https://stackoverflow.com/a/1057173/4954434
          https://stackoverflow.com/a/12830110/4954434

          以下将按预期工作。

          #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;
          }
          

          【讨论】:

            猜你喜欢
            • 2018-08-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-02-10
            • 2020-02-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多