C语言内置类型(你想知道的C语言 3.2)

Q: char类型、int类型和long类型的长度由什么决定?

A:  在不同的系统或编译系统上, int有时是2字节, 有时是4字节. 编译器决定着int究竟是2字节还是4字节.

      C语言标准没有规定int类型的准确长度, 因为它是标准, 不能太个性化。C语言只是粗略地规定char <= short <= int <= long.

      从编译器的角度, 它解析到int类型, 它是当做2字节还是4字节完全随性, 如果真想个性,也可以是5字节。

 

Q: 如何证明char类型和int类型的长度。

A:  使用sizeof得到长度显得太幼稚,用汇编看看它们的长度。

/*
   Xi Chen(511272827@qq.com)
   cxsjabcabc
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	char c = 'a';
	int i = 0xFFFEFDFC;

	printf("c: %p, i: %p\n", &c, &i);

	return 0;
}

我们期望可以通过堆栈中紧挨着的char类型和int类型变量的地址来确认.

c: 0x7ffeed4d474f, i: 0x7ffeed4d4748

  地址相差0x7: 变量是4字节对齐, char类型被填充3字节。

  代码对应汇编展示了c和i的地址是如何被rbp偏移表达。

   

    movb %0x61, (%rsi) 是单字节操作,对应char类型变量c.

    movl $0xfffefdfc, (%rdx) 是四字节操作,对应int类型变量i.

 

Q: 为什么c的地址和i的地址不是相差4字节?

A: 平台是Intel架构, little-endian. 广为流传的确认是否是小端法的代码:

/*
   Xi Chen(511272827@qq.com)
   cxsjabcabc
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int is_little_endian()
{
	short a = 0x1;

	return *(char *)&a == 0x1;
}

int main(int argc, char *argv[])
{
	int little_endian;

	little_endian = is_little_endian();

	printf("%s little endian!\n", little_endian ? "is" : "isn't");
	return 0;
}

  即判断一个超过1字节变量的低地址对应字节和变量低字节是否一致。

 

Q: 如何让c和i之间紧挨着,没有"填充的数据"?

A: 我们试着在char和int之间加一些可以造成对齐的变量。

/*
   Xi Chen(511272827@qq.com)
   cxsjabcabc
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	short h = 0xAABB;
	char c0 = 'b';
	char c = 'a';
	int i = 0xFFFEFDFC;

	printf("h: %p, c0: %p\n", &h, &c0);
	printf("c: %p, i: %p\n", &c, &i);

	return 0;
}

   但事与愿违,编译器根本不了解我们的心意,它不知道h和c0的存在是为了"padding",不同变量都会做所谓对齐处理。

h: 0x7ffee215c73c, c0: 0x7ffee215c73e
c: 0x7ffee215c73f, i: 0x7ffee215c738

 

Q: 结构体是提示编译器把变量放在一起,我们来试试。

A: 

/*
   Xi Chen(511272827@qq.com)
   cxsjabcabc
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

typedef struct __attribute((packed))
{
	char  c;
	int   i;
} char_int;

int main(int argc, char *argv[])
{

	char_int ci;
	
	printf("c: %p, i: %p\n", &ci.c, &ci.i);

	return 0;
}

   __attribute((packed))是为了变量中间不做padding, 按原生大小摆放。

  

c: 0x7ffee5e5c738, i: 0x7ffee5e5c739

 

作者:     陈曦
环境:     MacOS 10.14.5 (Intel i5)
         Apple LLVM version 10.0.1 (clang-1001.0.46.4)
         Target: x86_64-apple-darwin18.6.0
 
         Linux 3.16.83 (Ubuntu)
 
转载请注明出处

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值