【问题标题】:C - Behaviour of assigning char literals vs array literalsC - 分配字符文字与数组文字的行为
【发布时间】:2020-01-10 14:38:46
【问题描述】:

代码:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    union {
        int theInt;
        char theChar;
    } u1;

    u1.theChar = 'A';
    printf("%i\n", u1.theInt);
    printf("%c\n\n", u1.theChar);

    u1.theChar = "A";
    printf("%i\n", u1.theInt);
    printf("%c\n\n", u1.theChar);

}

给出输出:

65
A

45
-

在第一个分配中分配了字符“A”,在第二个分配中分配了数组“A”。为什么这两个赋值会导致不同的联合值?

【问题讨论】:

  • u1.theChar = "A"; 不能用标准编译器编译,所以这就是原因。请学习“Pointer from integer/integer from pointer without a cast” issues
  • 显然它使用 OPs 编译器编译,gcc 也可能只发出警告,但会生成二进制文件(当然,除非使用 -Werror)。
  • "A" 不是一个有效的 char 类型,它是一个字符串,如果你想打印 "A" 然后在 printf 中使用 %s 作为字符串。
  • @Ctx 没有“只有警告”之类的东西。有“它编译干净”和“它用诊断消息编译”。
  • @underscore_d 不是真的,因为这些例子谈到了int 类型而不是字符串文字。它也没有解决此代码中存在的多个联合类型双关语问题,这是第二个主要问题。我已经发布了解决这两个问题的答案。

标签: c arrays char


【解决方案1】:

在您的代码中

 u1.theChar = "A";

是错误的,因为 RHS,"A" 是一个字符串文字,它归结为一个指向包含字符 'A' 和终止 null 的数组的指针。不能将指针分配给char,这是违反约束的。

如果代码编译并生成二进制文件,执行将调用未定义的行为。

【讨论】:

    【解决方案2】:

    给出输出:65A

    不,不一定,因为代码调用了未定义的行为,因为 u1 未初始化且未获取其地址,请参阅 (Why) is using an uninitialized variable undefined behavior?

    未定义的行为 = 不知道会发生什么。在 32 位 little endian 系统上,它最多会打印 3 个字节的不确定垃圾,然后是第 4 个字节的 ASCII 值。我得到了一些垃圾2005012545。为了理解垃圾,我可以将其打印为十六进制:0x77821041,其中41 是包含 ASCII 值 0x41/65 的 LSB。

    这是因为您没有初始化 union,然后您可能正在运行一个调试版本,该版本恰好将所有堆栈值清零,因此该程序似乎适合您。

    通过将联合初始化为已知值来解决此问题:... } u1 = {0};


    至于u1.theChar = "A";,它甚至不能在正确配置的C 编译器上编译(参见"Pointer from integer/integer from pointer without a cast" issues)。因为字符串文字 "A" 在分配时最终会成为 char* 类型。但theChar 的类型为char。这也是未定义的行为,没有任何意义。充其量,您最终会得到来自字符指针地址的字节之一存储在theChar 中,但代码无效,所以不知道它会做什么。


    必要的修复:

    #include <stdio.h>
    
    int main (void)
    {
        union {
            int theInt;
            char theChar;
        } u1 = {0};
    
        u1.theChar = 'A';
        printf("%d\n", u1.theInt);
        printf("%c\n\n", u1.theChar);
    
        u1.theChar = "A"[0];
        printf("%d\n", u1.theInt);
        printf("%c\n\n", u1.theChar);
    }
    

    只要我们坚持小端系统,现在的输出是可预测的:

    65
    A
    
    65
    A
    

    大端 32 位系统应该给出这个输出:

    1090519040
    A
    
    1090519040
    A
    

    1090519040 = 0x41000000

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-03
      • 2013-08-04
      • 1970-01-01
      • 2010-12-30
      • 2013-03-26
      • 2012-09-29
      相关资源
      最近更新 更多