Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
具有union的C代码中出现意外输出_C_Unions - Fatal编程技术网

具有union的C代码中出现意外输出

具有union的C代码中出现意外输出,c,unions,C,Unions,我不理解以下C代码中的输出: #include <stdio.h> int main() { union U { int i; char s[3]; } u; u.i=0x3132; printf("%s", u.s); return 0; } 初始内存为32位,是0x3132的二进制值,即 0000 0000 0011 0001 0011 0010 如果0x3132的最后三个字节是不带前导零的s值,则s[0]=0011,

我不理解以下C代码中的输出:

#include <stdio.h>
int main()
{
   union U
   {
      int i;
      char s[3];
   } u;
   u.i=0x3132;
   printf("%s", u.s);
   return 0;
}
初始内存为32位,是0x3132的二进制值,即

0000 0000 0011 0001 0011 0010

如果0x3132的最后三个字节是不带前导零的s值,则s[0]=0011,s[1]=0001,s[2]=0011

这给出了s=0011 0001 0011=787的值


问题:为什么输出是21而不是787?

值0x3132在内存中表示为:0x32、0x31、0x0、0x0,因为字节顺序是小端的

printf调用打印出由联合的成员表示的字符串。字符串逐字节打印出来。首先是0x32,然后是0x31,它们是字符“2”和“1”的ascii值。然后打印停止,因为第三个元素是空字符:0x0


注意,int的表示是实现定义的,可能不包含4个字节,并且可能有填充。因此,union s的成员可能不代表字符串,在这种情况下,使用%s说明符调用printf将导致未定义的行为。

这意味着您的机器是little endian,因此字节以相反的顺序存储,如下所示:

32 31 00 00
#include <stdio.h>

int main( void )
{
    union U
   {
      int i;
      char s[3];
   } u;

   u.i=0x3132;
   printf("%s", u.s);
   printf( "%8x\n", (unsigned)u.i);
}
所以:s[0]=0x32,s[1]=0x31,s[2]=0x00


即使从理论上讲,使用%s打印字符数组是未定义的行为,它也会打印0x32字符“2”,0x31字符“1”,然后停止0x00。

首先查看此代码示例:

#include <inttypes.h> 
#include <stdio.h>
#include <stdint.h>
int main()
{
    union{
        int32_t i32;
        uint32_t u32;

        int16_t i16[2];
        uint16_t u16[2];

        int8_t i8[4];
        uint8_t u8[4];
    } u;

    u.u8[3] = 52;
    u.u8[2] = 51;
    u.u8[1] = 50;
    u.u8[0] = 49;

    printf(" %d %d %d %d \n", u.u8[3], u.u8[2], u.u8[1], u.u8[0]); // 52 51 50 49
    printf(" %x %x %x %x \n", u.u8[3], u.u8[2], u.u8[1], u.u8[0]); // 34 33 32 31
    printf(" 0x%x \n", u.i32); // 0x34333231

    return 0;
}
如图8所示:

那么输出是:

52 51 50 49
并读作int32\t:

那么输出是:

0x34333231
因此,正如您在本示例中看到的,代码联合使用许多名称/类型共享一个内存位置

在示例代码中,u.i=0x3132;这会在u.i内存中写入0x3132,这取决于您的系统的endianness,这里是小endian,然后您要求printf%s,u.s;从编译器中,u.s是char类型的数组,表示指向char类型的常量指针,所以这个printf%s,u.s;will读取u.s[0]并将其打印到输出标准输出上,然后读取u.s[1]并将其打印到输出标准输出上,依此类推,直到其中一个u.s[i]为零。
这就是您的代码所做的,因此,如果u.s[0]、u.s[1]、u.s[2]、u.s[3]中没有一个不为零,则将读取联合外部的内存,直到找到一个零或发生系统内存故障错误。

如果您这样编写代码:

32 31 00 00
#include <stdio.h>

int main( void )
{
    union U
   {
      int i;
      char s[3];
   } u;

   u.i=0x3132;
   printf("%s", u.s);
   printf( "%8x\n", (unsigned)u.i);
}
然后您会看到u.i的内容是0x0000000000003132,由于Endianness,它实际上会存储为:0x32310000000000

并且0x00不是可打印字符,因此第二次调用printf的输出是3132,正如您所期望的那样


ascii字符1为0x31,ascii字符2为0x32,第一个0x00停止%s操作,因此第一个printf输出21。

u.s不是字符串,不能使用%s打印。这在技术上是未定义的行为。已经说过,0x31==49==‘1’和0x32==50==‘2’,希望对你们来说是清楚的。最后两组8位在小字节0011 0010和0011 0001中,在十六进制中是32和31,在ASCII中是“2”和“1”。假设siZeFoT是没有任何填充位和字节序是小字节的,和ascii编码,那么这个行为就被定义了。为什么你认为应该是787呢?在设置int字段中位的预期顺序时,需要考虑Endianness。注意:当%s格式说明符看到一个0x00字符时,它会停止。这一定是意外按下了downvote按钮,请编辑您的帖子,以便我可以将其更改为upvote=很抱歉=
#include <stdio.h>

int main( void )
{
    union U
   {
      int i;
      char s[3];
   } u;

   u.i=0x3132;
   printf("%s", u.s);
   printf( "%8x\n", (unsigned)u.i);
}