嵌入式Linux C语言: 1.数据类型

计算机是如何给人类解决问题?
答: 问题域的数据保存起来,然后通过某些运算从而得到结果。
程序 = 算法 + 数据结构
首先考虑保存数据,在保存数据之前要知道数据的大小、范围和属性等,即数据类型

1. 数据类型

typeof(x) => 求对象x的类型

typeof(3) => int 
typeof(3.0) => double

可以利用typoeof对变量进行定义。

#include <stdio.h>

int main()
{
	typeof(1) a; // int a;
	return 0;
}

在c语言中,有如下数据类型:

基本类型:

C语言中已经定义好的类型,主要用来保存整数、小数和浮点数。

整数

(signed) char/unsigned char 字符型 保存ASCII的值(整数值)
signed: 有符号,可省略,下文均省略
short/unsigned short 短整型
int/unsigned int 整型
long/unsigned long 长整型

上面的类型都是用来描述整数
区别:
  a、signed/unsigned
   有符号(signed):
    符号位(最高位) + 数值位
        1 --> 负数
        0 --> 正数/0
    无符号(unsigned):
        所有bit位全部都是数值位(直接参与位运算)

整数用8bits来表示
如

1111 1110

=> unsigned(无符号):254
	1111 1110
	0000 0001 1
	--------- +
	1111 1111
	0000 0001 1
	--------- +
   10000 0000 256
  所以:1111 1110 = 256-1-1 = 254
  
=> signed(有符号):
 计算方法如下: 
  	负数 => |负数| => 取反 => +1 => 负数补码
  	负数补码 => -1 => 取反 => |负数| => 负数
  		1111 1110
  		0000 0001 1
  		--------- -1
  		1111 1101
  		0000 0010 取反(~)
  		0000 0010 |2|
  		1111 1110 -2
  			1111 1110
  		-1: 1111 1101
  	   取反: 0000 0010
  	   |2|: 0000 0010
  	   -2: 1111 1101

  b、char/short/int/long/…
    所占内存空间大小不同

数据类型所占空间大小取值范围二进制取值范围
char8bits(1byte)[-128,127]1000 0000 – 0111 1111
unsigned char8bits(1byte)[0,255]0000 0000 – 1111 1111
short/unsigned short在32位机器下,一般为32bits(4bytes);在64位机器下,一般为32bits(4bytes)--
long/unsigned long在32位机器下,一般为32bits(4bytes);在64 位机器下,一般为64bits(8bytes)--

  c、在不同的编译器下面,同一类型的范围也不一样

keil
	int 16bits(2bytes)
unbuntu 18.04
	int 32bits(4bytes)

   sizeof(x) 求类型x所占的字节数,默认为长整型(%ld)
      1bytes = 8bits
    一般整型类型的所占内存空间大小关系
      sizeof(long) >= sizeof(int) >= sizeof(short) >= sizeof(char)

  d、在gcc编译器中,整数默认类型为 int
      typeof(3) => int
      typeof(3+4) => int
      typeof(3+4.0) +> double

小数(浮点数)
数据类型名称
float单精度浮点型
double双精度浮点型
long double长双精度浮点型

区别:
  a、类型不同,所占空间不同,保存精度也不同
    一般来说:
        sizeof(float) => 4bytes
        sizeof(double) => 8bytes
        sizeof(long double) => 16bytes(64位机器)

 b、在gcc编译器中,浮点数默认类型为double
        typeof(2…0) => double
        typeof(2.0f) => float
        typeof(2) => int
        typeof(2u) => unsigned int
        typeof(2.0 + 3) => double

构造类型

自定义类型
数组: 一组相同类型元素的数据集合

int a[10]; //定义一个数组,数组名为a,含有10个int类型的元素
定义变量: 变量类型 + 名字
定义一个像a一样的对象m
typeof(a) m;

结构体
自定义的一种组合类型

struct 结构体名
{
  成员类型1 成员名1;
  成员类型2 成员名2;
  …
  成员类型n 成员名n;
};
结构体类型是由多个成员构成,而且每个成员都有自己的类型(只要是合法的C语言类型都可以),当然不同的成员,类型可以相同,成员名不能相同。
后续会详细讲解结构体

联合体(共用体)
联合体(公用体)的存储空间是各成员之间公用的
同一时刻只能用一个成员变量,为了节省空间才提出 共用体

union 共用体名
{
  成员类型1 成员名1;
  成员类型2 成员名2;
  …
  成员类型n 成员名n;
};
后续会详细讲解共用体

共用体和结构体最大的区别:
结构体所占内存大小是各成员变量值和
共用体所占内存大小是各成员变量之间那个最大成员所占的内存空间

枚举
把该类型变量所有可能的值一一列举出来。
所以枚举类型一定是可以一一列举的值,也就是整数值。

enum 枚举类型名
{
  枚举具体值
};
C语言实现枚举时,枚举的具体的值是用一个整数值来表示的。

后续会详细讲解枚举

指针类型

指针变量: 保存一个对象的地址的变量
指针变量也是一个变量,在定义指针变量的时候,为了区分,在指针变量的前面加一个"*"表示是一个指针变量

指向的对象的类型 * 指针类型名

后续会详细讲解指针

void类型

void 在C语言中,有三个作用:
  1. void*
    通用指针,用来存放任何数据类型的引用(指针)
    当不清楚所需指针类型时使用
      void*
        char*
        int*
        short*
        …

malloc(100); //与C++中new相同 返回void*类型指针,占空间用
开辟100字节大小的空间
在指针中会详细讲解malloc这个函数

  2. void当作函数的参数
    表示此函数没有参数,不需要传参,可省略

int func(void){}
调用
函数名(实参)
func(3, 4);		 //ERROR func函数的参数为void 不需要穿参
func();			//TRUE 正确调用

  3. void 当作函数的返回值类型
    表示函数没有返回值,不需要返回值

void func(int m, int n)
{
	return ;	//TRUE
	return 0;	//ERROR 该句话表示,退出函数,并返回0,func函数的返回值类型为void,不需要返回值
}

2.变量和常量

在C语言中,数据分为两大类:变量和常量

变量

什么是变量?
  在程序运行期间,可以改变其值的数据对象
  存储变量会对应一个存储单元且存储单元是可写的

变量的定义
  变量在使用前必须定义
语法
  变量类型 变量名 (= 初值);
  可以赋值也可以不赋值

  变量类型
    基本类型、构造类型、指针类型

  变量名
    一个对象的名字,标识符(对象的名字,可以是变量、数组或函数)
    在C语言中,C语言标识符: 只能由字母、下划线和数组组成,但是数字不能开头
      为什么数字不能开头
      int 2E3; //2E3 科学记数法 2000

如果在定义变量时,没有给变量赋初值,编译器会随机赋一个值给这个变量

int a;
printf("%d\n, a"); //打印随机值,由编译器决定

变量的属性

int a = 1024;
int: 变量类型
a: 变量名
1024: 变量值(存储空间中保存的内容)
&a: 变量的地址

一个变量有如下属性:
  变量类型
  变量名
  变量值(保存到存储空间中的内容)
    变量的存储空间中的内容,不管是否初始化或赋值,空间中一定会有一个值,因为存储空间中所有的bit为都有值,只为0或1
  变量的地址:
    在程序运行时,程序会为每一个变量分配一个存储空间,用来保存这个变量的值,且这个存储空间一定会有一个唯一的编号,那么这个编号就是变量的地址

变量的访问(read/write)

int b, a=5;	
a = 1024;	//把1024写到变量a所对应的地址中 将数值写到a的地址 ---- (1)
b = a*5;	//把a的值乘5,赋值给b 读取变量a的值 ---- (2)

读(read): 从变量的存储单元中读取存储单元中的内容,读变量的值
写(write): 把一个值写到变量所对应的存储单元中 赋值

在C语言中,任何变量有且只有两层含义:
  1. 变量的地址
    lvalue:
      location value 可寻址(可写)的值
      left value 左值
 1. 变量的值:
    rvalue:
      readable value 可读的值
      right value 右值

一般情况
变量的左值:
  变量的地址,"=“的左边
变量的右边:
  变量的值,”="的右边

整数

在计算机中整数是以其补码形式保存的
整数有正数、0和负数

正数/0
整数的补码就是其原码的本身
原码:就是相对应的数值转换为二进制形式

13: int 32bit
13=8+4+1
00000000 00000000 000000000 00001101(在后续为了方便会对部分0进行省略)
int a=13;
a:
	00000000 00001101

负数
负数的补码 其原码的绝对值 取反 +1

-13 int 32bits
|-13|: 00000000 0000000 0000000 00001101
取反:  11111111 11111111 11111111 11110010
+1:   11111111 11111111 11111111 11110011
-13的补码: 11111111 11111111 11111111 11110011

8bit 存储:
-2: 1111 1110
254: 1111 1110

-3: 1111 1101
253: 1111 1101

-4: 1111 1100
252: 1111 1100

一个负数会和一个正整数以一样的形式存放在计算机中

-x 和 (2^n - x) 相同 n表示用n个bits存储一个整数

n=32时
 -1和2^32-1相同

CPU内无符号位,对CPU来说,所有的bit位都是数值位参与运算

int a = -13;
a在计算机中的存储形式为
11111111 11111111 11111111 11110011

printf("%d\n", a); //-13
%d:有符号数
符号位: 1
负数补码: 11111111 11111111 11111111 11110011
	减1: 11111111 11111111 11111111 11110010
   取反: 00000000 00000000 000000000 00001101
  |-13|: 00000000 00000000 000000000 00001101
   负数: -13

printf("%u\n", a); //2^32 - 13
%u: 无符号数 正数/0
1111111 11111111 11111111 11110011 既是补码也是原码
2^32 - 13
unsigned int a = -1u;
0u表示无符号整型0,1u表示无符号整型1
-1u表示无符号整型的最大值,即32个bit为全为1
-1u: 11111111 11111111 11111111 11111111
  a: 11111111 11111111 11111111 11111111
  
 printf("%d\n", a); //-1
 printf("%u\n", a);  //2^32-1

untsigned int a = 1<<31;
1<<31: 10000000 00000000 00000000 00000000
printf("%d\n", a); //-2^31
%d: 有符号数
 -1: 01111111 11111111 11111111 11111111
取反: 10000000 00000000 00000000 00000000
|-2^31|
-2^31

printf("%u\n", a); //2^31
%u: 无符号数
10000000 00000000 00000000 00000000
2^31 = 2^32 - 2^31

在GNU有一个标准头文件 stdint.h 中定义了几种扩展的整数类型和宏
路径: /user/include/stdint.h

整数之间赋值
 char a = 123;
 int b = 1024;
 a = b; //不会报错,但结果会出错
  在C语言中,允许不同类型之间整数相互赋值,不同类型的整数,存储空间大小不同
  char 8bits
  short 16bits
  int 32bits
  …

 C标准建议
  1. 长变短
    低字节直接拷贝,高字节部分全部舍弃 无法保存
  2.短变长
    低字节直接拷贝
    高字节:如果短的是无符号为,高位全部补0;如果短的是有符号数,高位补符号位
   从右往左运算

char a = 127; 
int b = 1024; 
a = b;
printf(%d\n", a); //0
printf("%u\n", a); //0

a: 01111111
127: 00000000 00000000 00000000 01111111
长变短 高字节直接舍弃

b: 1024 2^10
b: 00000000 00000000 00000100 00000000

a=b
a:char类型 b:int类型 
int -> char 长变短
a: 00000000

%d:有符号位,符号位位0 正数 值为0
%u:无符号 值为0
char a= 250;
char d;
d = a+8;
printf("%d\n", d);	//2
printf("%u\n", d);	//2

250: 256 - 2 - 4
00000000 00000000 00000001 00000000 256
00000000 00000000 00000000 00000010 2
--------------------------------- -
00000000 00000000 00000000 11111110
00000000 00000000 00000000 00000100 4
--------------------------------- -
00000000 00000000 00000000 11111010 

250: 0000000 00000000 0000000 11111010
a:11111010 长变短

d = a+8;
a char 与 8 int型进行加减 先短变长
11111111 11111111 11111111 11111010 a (int)
00000000 00000000 00000000 00001000 8
----------------------------------- +
00000000 00000000 00000000 00000010 a+8
d是char型 长变短
d: 00000010

%d: 2
%u: 2
常量

常量是在程序运行期间,值不能改变
  1. 整型常量
    代表整数的常量值

    八进制常量: 以0开头,后接多个0-7字符组成
      0[0-7]+ (正则表达式的表示方法)
        如:
          0000
          0123
          0923 //ERROR 八进制中无9
      int a = 0123;
      printf(“%d\n”, a); //八进制转换十进制

    十六进制常量: 以0x和0X开头,后面接多个或者一个0-9, a-f,A-F字符
      0[x/X][0-9, a-f, A-F]+
        如:
          0xF
          012F //ERROR 八进制中无F
      int a = 0xf3
      printf(“%d\n”, a); //十六进制转十进制 253

    十进制常量:
      [0-9]+

  2. 字符常量
    字符常量是用单引号引起来的一个或多个字符的序列
      如:
        ‘a’
        ‘A’
        …
        ‘\n’ 换行
        ‘\r’ 回车
        ‘\t’ 制表
        …
        ‘\0’ ASCII为0 对应的字符

在计算机中,保存一个字符,保存的是字符对应的ASCII码值
ASCII:
  American Standard Code for Information Interchange
  漂亮国把每个字符给唯一的整数值来表示,这个整数值就是ASCII码。由于漂亮国使用字符不超过256个,所以只需要8bits就可以保存。
  使用 man ASCII可查看相关信息
ASCII码的主要内容有:
  Oct: 八进制
  Dec: 十进制
  Hex: 十六进制
  Char: 字符
  “A” - “Z” : 65-90
  “a” - “z” : 97-122
  “0” - “9” : 48-57

    字符分为两种
      a、普通字符
        可以打印的字符,有形状的字符
      b、 特殊字符(转义字符)
        不可打印的字符
        如:
          ‘\n’ 换行符
          ‘\t’ 制表符
          ‘\r’ 回车符
          …
          ‘\000’:由\后面接一个、两个或三个八进制的数字组成,这些八进制数字用来制定所期望的字符的ASXII码值
            如: ‘\101’ <=> 65 <=> 0x41 <=> ‘A’
        ‘\0x00’: 由\x后面接一个或两个十六进制数字组成。十六进制数字用来制定所期望的字符的ASCII值

  3.浮点常量
    由整数部分、小数点、小数部分、一个e/E、一个可选的带符号的整数指数 和 一个可选的表示类型的后缀(f/F/l/L)组成
      f/F: float
      l/L: long double
      没有后缀: double

      整数部分: 可省略
      小数部分: 可省略
        但是小数部分 和 整数部分不能同时省略
        如:
          float f = 2.3E3; // 2.3*10^3
          float f = .3E3; // 0.3*10^3
          float f = 5E-5; //5.0*10^-5
          float f = E5; //ERROR 小数和整数部分不能同时省略(与变量无法区分)

 4. 枚举常量
    枚举类型是整数值,可列举的常量值

 5. 符号常量
    宏
      #define 宏名 替换对象
      如: #define PI 3.14

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值