我不理解以下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 0000 0000 0011 0001 0011 0010
。
如果0x3132
的最后三个字节是s
的值(没有前导零),那么s[0]=0011,s[1]=0001,s[2]=0011
。
这给出了s=0011 0001 0011=787
。
问题:为什么输出为21
而不是787
?
答案 0 :(得分:4)
值0x3132在内存中表示为:0x32,0x31,0x0,0x0,因为字节顺序是小端。
printf调用打印出由union s
成员表示的字符串。字符串逐字节打印出来。首先是0x32,然后是0x31,它们是字符的ascii值:'2'
和'1'
。然后打印停止,因为第三个元素是空字符:0x0。
请注意,int的表示是实现定义的,可能不包含4个字节,可能有填充。因此,union s
的成员可能不表示字符串,在这种情况下,使用%s
说明符调用printf将导致未定义的行为。
答案 1 :(得分:2)
首先看到此代码示例:
#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;
}
这里的联盟只是以6种不同的方式访问u
的记忆
您可以使用u.i32
来读取或写为int32_t
或
您可以使用u.u32
来读取或写为uint32_t
或
您可以使用u.i16[0]
或u.i16[1]
来读取或写为int16_t
或
您可以使用u.u16[0]
或u.u16[1]
来读取或写为uint16_t
或
或像这样写为uint8_t
:
u.u8[3] = 52;
u.u8[2] = 51;
u.u8[1] = 50;
u.u8[0] = 49;
并像int8_t
一样阅读:
printf(" %d %d %d %d \n", u.u8[3], u.u8[2], u.u8[1], u.u8[0]);
然后输出:
52 51 50 49
并阅读为int32_t
:
printf(" 0x%x \n", u.i32);
然后输出:
0x34333231
正如您在此示例中所看到的,代码联合共享一个具有许多名称/类型的内存位置。
在您的示例代码u.i=0x3132;
中,这会在0x3132
内存中写入u.i
,并且根据您的系统的字节顺序(这里是小端),然后您从printf("%s", u.s);
询问了char
编译器,所以我们是类型printf("%s", u.s);
的数组,意味着指向char类型的常量指针,因此这个u.s[0]
将读取stdout
并在输出u.s[1]
上打印然后读取{{1}并在输出stdout
上打印,依此类推...,直到其中一个u.s[i]
为零。
这是你的代码所做的,所以如果我们[0],我们[1],我们[2],我们[3]都不为零,那么你的联盟之外的内存将被读取,直到发现一个零或系统内存故障error
发生了。
答案 2 :(得分:1)
这意味着你的机器是 little-endian ,因此字节以相反的顺序存储,如下所示:
32 31 00 00
所以:s[0] = 0x32, s[1] = 0x31, s[2] = 0x00.
即使在理论上使用"%s"
打印一个字符数组是未定义的行为,这是有效的,它会打印0x32 (character '2')
,0x31 (character '1')
然后它会停止0x00。
答案 3 :(得分:0)
如果您编写这样的代码:
<item name="android:scrollbarThumbVertical">@color/transparent</item>
if you don't have a transparent color defined in colors.xml, use the android library "transparent" with: <item name="android:scrollbarThumbVertical">@android:color/transparent</item>
然后你会看到u.i的内容是0x0000000000003132,由于Endianness,它实际上会被存储为:0x3231000000000000
和0x00不是可打印字符,因此第二次调用#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);
}
的输出为printf()
正如您所期望的那样
,ascii char <blank><blank><blank><blank><blank><blank>3132
为0x31,ascii char 1
为0x32,第一个0x00停止%s操作,因此第一个2
输出printf()
。< / p>