嵌入式Linux C(二)——数据类型(详)

一、数据类型

分类:
基本数据类型:(内置:编译器自带的类型):int(4)、short(2)、long(8)、long long、char(1)、float(4)、double(8)
复合数据类型:(多个内置类型的组成的新类型):数组、union、struct、enum
void类型:void *(万能指针):多态

二、定义变量

(注意事项:编码规范

  • 变量的可读性 形容词_名词 (不允许用拼音命名!!!) int n; int sum_result;
  • 循环变量:int i;int k;

三、基本数据类型需掌握的知识点

3.0 类型转化

C语言类型转换:不安全,可以将任何类型之间转换,有可能造成数据丢失(可以隐式输出,直接编译)
安全的类型转换:先检查两个类型是否可以转换
强制类型转换:(类型名称)变量名
如果一个运算符两边的运算数类型不同,先要将其转换为相同的类型,即较低类型转换为较高类型,然后再参加运算,转换规则如下图所示。
在这里插入图片描述

3.1 各种数据类型的字节长度

(变量占用内存的大小:字节)int num = 5;

注:计算机便是内存大小的单位:8bit位 = 1个字节、16bit = 2个字节 = 半字、32bit = 字、双字、kb

1. 数据类型长度

int len = sizeof(num);//sizeof计算数据类型和变量的内存大小
//int len = sizeof(int);
sizeof是一个运算符

int num;
int len = sizeof num; //√
int len = sizeof int;//×
int len = sizeof(num);//√

2. 指针长度

  • 指针的长度:int *; char *
  • 指针类型:保存地址,操作系统中地址的长度是固定的,是由操作系统位数决定的,64位系统是8个字节、32位系统是4个字节

3. 数组长度

int arry_int[100];//400
char arry_char[100];//100

4. 字符串长度

字符串的长度:int strlen(char *stc) //不统计’\0’

#include <stdio.h>
#include <string.h>

int main()
{
    char *ptr = "hello world";
    printf("sizeof(*ptr) = %ld\n",sizeof(ptr));
    printf("strlen(*ptr) = %ld\n",strlen(ptr));
    printf("strlen(hello world) = %ld\n",strlen("hello world"));
    return 0;
}

结果
小结:如何测量数据类型的大小

sizeof运算符
sizeof(变量名)
sizeof (数据类型)
strlen 统计字符串中字符的个数

3.2 各种数据类型的取值范围

(计算机是以补码形式保存数据,为解决+0 -0问题)
原码、反码、补码
计算机里保存:补码
正数:原码 = 补码
负数:
补码 = 原码取反 + 1
原码 = 补码取反 + 1
unsigned char:0 - 255(2^8-1)
signed char:-128-127

  • 0 000 0000 = 0
  • 0 111 1111 = 127
  • 1 000 0000 = -128
    111 1111
    +1 = 2^7 - 1 + 1
    1 000 0000 =-128
  • 1 111 1111 = -1
    000 0000
    +1
    1 000 0001 = -1

计算机为什么提出补码存储?
解决 +0 与-0
0 000 0000 = +0
1 000 0000 = -0

printf("%d",~2)
0000 0010
1111 1101
000 0010
+1
1 000 0011 = -3

//例
char ch = -128;
ch = ch - 1; //溢出
//计算机不做减法,只做加法
//1 000 0000 //-128
//1 111 1111 //-1
//0 111 1111 = 127//上面两个相加得出结果
//例
char a[1000]
for (int i = 0; i < 1000; i++)
{
	a[i] = i - 1;
	//i = 127   a[127]  =  -128
	//i = 128   a[128]  =  127
	//i = 128   a[129]  =  126
	//..
	//i = 255   a[255]  =  0;   ‘\0’
}
printf("strlen(a) = %ld\n",strlen(a));
//结果是255  可以好好想想
//例1
char ch =127;
ch = ch + 1;
printf("%d",ch);// 溢出,输出-128
//例2
char ch =127;
printf("%d",ch + 1);//输出128

//例1,是+1后回写到内存中,造成溢出
//例2,是直接输出,所以不存在回写

3.3 无符号和有符号的移植性

signed VS unsigned
有的编译器默认是有符号,有的是无符号
如果不解决,可能导致不同编译器,编译出错

typedef

关键字:给数据类型重命名
typedef unsigned char uChar;
typedef signed char Char;
typedef unsigned int len; //命名易懂
typedef struct student Stu; //结构体重命名,提高编码效率

  • 解决signed、unsigned带来的代码移植性的问题
  • 提高代码的可读性
  • 提高编码效率

四、变量和常量

  • 全局变量和局部变量:字节长度、生命周期、存储区域
  • 作用域:可见范围
    局部变量:在函数体里定义的变量–所在函数(出了函数不可见)
    全局变量:在函数体外定义的变量–整个全局(需要用外部声明)extern int g_count
  • 生命周期:所在内存空间的分配-释放的过程
    局部变量:所在函数体执行时,分配空间,执行结束、释放空间
    全局变量:所在程序执行时,分配空间,执行结束,释放空间
  • 存储区域
    CPU、硬盘、内存(物理内存,属于稀缺资源)
    概念:物理内存与虚拟内存

vim hello.c
gcc hello.c -o hello
存储在硬盘上

CPU读取内存,运算完,回写内存

int num = 5;
*(&num) = 10;
printf("%p\n",&num);
//这个地址在是虚拟内存空间,以便用户不能轻易的访问到物理内存

操作系统会给用户4G的虚拟地址,通过MMU,实现虚拟地址空间(VA)与物理地址空间(PA)的映射
内存4G:1G内核+3G(栈空间、堆空间、数据段、代码段)

  • 栈空间:
    存放:局部变量、函数形参、自动变量(少)
    特点:先进后出、系统管理(操作系统决定释放与分配)
  • 堆空间:
    存放:malloc、ralloc、calloc分配的空间
    特点:先进先出、用户管理
  • 数据段
    再划分:
    bss:未初始化的全局变量
    or:常量
    静态数据区:static修饰静态变量、初始化的全局变量

初始化未定义,高版本都是0

局部变量:存储在栈空间
全局变量:存储在数据段

五、格式化输出

unsigned int usi_num = 5;
signed int si_num = -5;

int array[3] = {1,2,3};

char ch = 'a';
char *ptr = "hello world";
char src[100] = "hello";

short s_sum = 6;
long l_num = 12345678;

float f_num = 1.123;

double d_num = 1.324;

printf("usi_num = %u\n",usi_num);
printf("si_num = %d\n",si_num);

for(int i = 0; i < sizeof(array)/sizeof(int); i++)
{
	printf("array[%d] = %d\n",i,array[i]);
}

printf("ch = %c\n",ch);
printf("ptr = %s\n",ptr);
while(*ptr != '\0')
{
	printf("%c\n",*ptr);
	ptr++;
}

//数组名保存数组首元素地址
printf("src = %s\n",src);

printf("s_sum = %d\n",s_sum);

printf("l_sum = %ld\n",l_sum);

printf("d_sum = %lf\n",d_sum);

printf注意点

printf:行缓冲:满一行(4096)或者遇到’\n’或者被强行输出时,数据才会被输出
printf语句后面要加上\n

printf("hello world!");
while(1);//不输出

printf使用技巧

printf使用技巧:C语言printf()函数中一些不为人知的技巧!

格式化输入

scanf格式化才能输入
注意点

  • 不加\n
  • 加&
  • 指针类型不兼容(%hd、%ld)
  • 跳出数组时,加上\0
  • getchar()处理垃圾
  • 数据溢出,很危险
  • 遇到空格就停止
    gets();获取句子,无缓冲

  • 计算机不做减法,只做加法
  • 在c语言中,用typedef重命名后,原来的变量名还可以用
  • MMU的解释:内存管理单元MMU
  • 定义只能定义一次,而声明可以声明很多次。先声明,再使用
  • 指针需要给其地址

疑问及其解决

疑问1::printf("%d",~2)为什么不直接是正数 1111 1101
在这里插入图片描述
解决1:
在这里插入图片描述
默认确实是有符号型,所以要看符号位
疑问点2:
unsigned char和unsigned int一样吗?为什么都是输出-3
解决2:
char是8个bit=1个字节
int是32个bit=4个字节(VC中是4个字节、ANSI标准定义中是2个字节)
关于bit等概念,数据范围看:
32位操作系统int类型最大值是多少?
疑问3
大数问题
利用数组连续性,将大数每一位上的数字单独取出放入对应的数组单元中,然后再对每一位做单独的加减乘运算,期间需处理好进位和借位以及其它一些细节性的问题。
疑问4
typedef VS 宏

typedef与#define的区别

typedef只是为了增加可读性而为标识符另起的新名称(仅仅只是个别名),而#define原本在C中是为了定义常量,到了C++,const、enum、inline的出现使它也渐渐成为了起别名的工具。有时很容易搞不清楚与typedef两者到底该用哪个好,如#define INT int这样的语句,用typedef一样可以完成,用哪个好呢?我主张用typedef,因为在早期的许多C编译器中这条语句是非法的,只是现今的编译器又做了扩充。为了尽可能地兼容,一般都遵循#define定义“可读”的常量以及一些宏语句的任务,而typedef则常用来定义关键字、冗长的类型的别名。

宏定义只是简单的字符串代换(原地扩展),而typedef则不是原地扩展,它的新名字具有一定的封装性,以致于新命名的标识符具有更易定义变量的功能。请看:

typedef (int*) pINT;

以及下面这行:

#define pINT2 int*

效果相同?实则不同!实践中见差别:pINT a,b;的效果同int *a; int *b;表示定义了两个整型指针变量。而pINT2 a,b;的效果同int *a, b;表示定义了一个整型指针变量a和整型变量b。
  转自:typedef与宏定义区别

编程实训

题目:实现一个计算器,功能加减乘除

#include <stdio.h>

int main()
{
	int num_1,num_2,result;
	char run_num; 
	printf("输入需要运算的两个数,并用逗号隔开:\n"); 
	scanf("%d,%d",&num_1,&num_2);
	printf("输入运算符,如*,/,+,-\n");
	getchar();
	scanf("%c",&run_num);
	
	switch(run_num)
	{
		case '+':
		{
			result = num_1 + num_2;
			break;
		}
		case '-':
		{
			result = num_1 - num_2;
			break;	
		}
		case '*':
		{
			result = num_1 * num_2;
			break;	
		}
		case '/':
		{
			result = num_1 / num_2;
			break;	
		}
		default:
			{
				printf("error!");
			}
	} 
	printf("%d %c %d = %d",num_1,run_num,num_2,result);
	 
	return 0;
}

作业

  1. 设定输入长度
  2. 密码保护
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周末不下雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值