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

简介: 嵌入式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语言类型转换:不安全,可以将任何类型之间转换,有可能造成数据丢失(可以隐式输出,直接编译)

安全的类型转换:先检查两个类型是否可以转换

强制类型转换:(类型名称)变量名

如果一个运算符两边的运算数类型不同,先要将其转换为相同的类型,即较低类型转换为较高类型,然后再参加运算,转换规则如下图所示。


0a2653c851af460fa595bd959398a8f1.png


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;
}

0a2653c851af460fa595bd959398a8f1.png

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


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

0a2653c851af460fa595bd959398a8f1.png

解决1:

2d65d23f6d4748949b924e4057485923.png

默认确实是有符号型,所以要看符号位

疑问点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.密码保护

相关文章
|
15天前
|
JSON 机器人 Linux
推荐一款嵌入式Linux开源框架与封装-cpp-tbox
推荐一款嵌入式Linux开源框架与封装-cpp-tbox
48 3
|
1月前
|
存储 Linux C语言
Linux系统下C语言的构造数据类型
Linux系统下C语言的构造数据类型
12 0
|
1月前
|
Linux 开发工具 git
Linux嵌入式系统中如何使用U-Boot实例
Linux嵌入式系统中如何使用U-Boot实例
26 0
|
3天前
|
Linux 编译器 测试技术
嵌入式 Linux 下的 LVGL 移植
嵌入式 Linux 下的 LVGL 移植
|
16天前
|
Linux
嵌入式Linux系统(NUC980)tf卡出错处理errors=remount-ro改为errors=continue
嵌入式Linux系统(NUC980)tf卡出错处理errors=remount-ro改为errors=continue
7 1
|
17天前
|
安全 Linux
嵌入式Linux系统关闭串口调试信息的输出
嵌入式Linux系统关闭串口调试信息的输出
13 1
|
17天前
|
Linux 编译器 网络安全
嵌入式Linux移植dropbear
嵌入式Linux移植dropbear
16 3
|
17天前
|
存储 Ubuntu Linux
制作一个嵌入式Linux的应用程序升级文件
制作一个嵌入式Linux的应用程序升级文件
12 2
|
17天前
|
传感器 Linux API
嵌入式Linux串口编程简介
嵌入式Linux串口编程简介
15 1
|
23天前
|
存储 安全 Linux
嵌入式Linux系统bringup 启动全景解析
嵌入式Linux系统bringup 启动全景解析
70 0