从零开始学嵌入式技术之C语言05:数据类型

        程序的主要目的就是对数据进行计算和处理,为了方便数据的管理,通常会对数据进行分类。就像根据容器的容量和形状不同,可以分成大杯中杯、大碗小碗等,不同的容器适合装不同的东西。

        C语言根据数据的特性和用途进行了类型划分,不同类型的数据在内存中占据不同大小的空间。

一:整数类型

        整数类型简称整型,就是用于存放整数值的,比如:12,30,3456等。

类型

存储大小

值范围

short  

signed short

2 字节

-32,768 (- 2^15)到 32,767 (2^15 -1)

unsigned short

2 字节

0 到 65,535 (2^16 - 1)

int

signed int

16位:2 字节

32位:4 字节

16位:-32,768 (- 2^15 ) 到 32,767 (2^15-1)

32位:-2,147,483,648 (- 2^31) 到 2,147,483,647 (2^31 -1)

unsigned int

16位:2 字节

32位:4 字节

16位:0 到 65,535 (2^16-1)

32位:0 到4,294,967,295(2^32 -1)

long

signed long

32位:4 字节 64位:8 字节

32位:-2,147,483,648 (- 2^31) 到 2,147,483,647 (2^31 - 1)

64位:9223372036854775808(-2^63) 到9223372036854775807 (2^63-1)

unsigned long

4 或 8 字节

32位:0 到 4,294,967,295 (2^32 - 1)

64位:0 ~ 18446744073709551615 (2^64 - 1)

long long

signed long long

8字节

9223372036854775808(-2^63) 到9223372036854775807 (2^63-1)

unsigned long long

8 字节

0 ~ 18446744073709551615 (2^64 - 1)

关于存储大小单位:

bit(位):计算机中的最小存储单位,表示一个二进制位。

byte(字节):计算机中基本存储单元,1byte = 8bit。

(1)整型注意事项

        各类型存储大小受到操作系统、编译器、硬件平台的影响。

        整型分为有符号signed和无符号unsigned两种,默认是signed。

        开发中使用整型一般用int型,如果不足以表示大数,可以使用long long。

(2)字面量后缀

        字面量是源代码中一个固定值的表示法,用于直接表示数据

        一个整数字面量默认是int类型。

        如果需要表示 long 类型字面量,需要添加后缀 l 或 L。

        如果需要表示 long long 类型字面量,需要添加后缀 ll 或 LL。

        如果需要表示无符号整数字面量,需要添加后缀 u 或 U, 注意, u 和 l 可以结合使用,不分先后,如 ul(无符号long类型)、ULL(无符号 long long类型),lu(无符号 long 类型) 等。

(3)格式占位符

  1. %d 对应 int 类型,%u 对应 unsigned int 类型。
  2. %hd 对应 short 类型,%hu 对应 unsigned short 类型。
  3. %ld 对应 long 类型,%lu 对应 unsigned long 类型。
  4. %lld 对应 long long 类型,%llu 对应 unsigned long long 类型。
#include <stdio.h>

int main()
{
    // short 类型
    short a1 = 10;  // 等同于 signed short a1 = 10;
    short a2 = -10; // 等同于 signed short a1 = -10;
    // unsigned short a3 = -20;
    unsigned short a3 = 20;
    printf("a1=%d; a2=%d; a3=%d \n", a1, a2, a3); // a1=10; a2=-10; a3=20

    // int 类型
    int b1 = 100;  // 等同于 signed int a1 = 100;
    int b2 = -100; // 等同于 signed int a1 = -100;
    unsigned int b3 = 200u;
    unsigned b4 = 300U;                                      // 等同于  unsigned int b4 = 300U;
    printf("b1=%d; b2=%d; b3=%d; b4=%d \n", b1, b2, b3, b4); // b1=100; b2=-100; b3=200; b4=300

    // long 类型
    long c1 = 1000l;   // 等同于 signed long c1 = 1000l;
    long c2 = -1000L; // 等同于 signed long c2 = -1000L;
    unsigned long c3 = 2000ul;
    printf("c1=%ld; c2=%ld; c3=%ld \n", c1, c2, c3); // c1=100; c2=-1000; c3=2000

    // long long 类型
    long long d1 = 10000ll;  // 等同于 signed long long d1 = 10000ll;
    long long d2 = -10000LL; // 等同于 signed long long d2 = -10000LL;
    unsigned long long d3 = 20000ULL;
    printf("d1=%lld; d2=%lld; d3=%lld \n", d1, d2, d3); // d1=10000; d2=-10000; d3=20000

    return 0;
}

        C 语言的整数类型(short、int、long)在不同计算机上,占用的字节宽度可能是不一样的。程序员有时需要精准的字节宽度,以提高代码的可移植性,尤其是嵌入式开发中,使用精确宽度类型可以确保代码在各种平台上的一致性。

标准库的头文件 <stdint.h> 中定义了一些新的类型别名,如下:

类型名称

含义

int8_t

8 位有符号整数

int16_t

16 位有符号整数

int32_t

32 位有符号整数

int64_t

64 位有符号整数

uint8_t

8 位无符号整数

uint16_t

16 位无符号整数

uint32_t

32 位无符号整数

uint64_t

64 位无符号整数

上面这些都是类型别名,编译器会指定它们指向的底层类型。比如,某个系统中,如果 int 类型为32位, int32_t 就会指向 int ;如果 long 类型为32位, int32_t 则会指向 long 。

示例代码:

#include <stdio.h>
#include <stdint.h>

int main()
{
    // 变量 x32 声明为 int32_t 类型,可以保证是32位(4个字节)的宽度。
    int32_t x32 = 45933945; 
    printf("x32=%d\n", x32);
    return 0;
}

 二:浮点类型

        浮点类型可以表示一个小数,比如:123.4,7.8,0.12等。

类型

存储大小

值范围

有效小数位数

float 单精度

4 字节

1.2E-38 到 3.4E+38

6 ~ 9

double 双精度

8 字节

2.3E-308 到 1.7E+308

15 ~18

long double 长双精度

32位:10字节

64位:16字节

32位:与 double 相同或更大

64位:3.4E-4932到1.2E+4932

18或更多

 (1)浮点型注意事项

        各类型的存储大小和精度受到操作系统、编译器、硬件平台的影响。

        浮点型数据有两种表示形式:

                十进制数形式:如:5.12、512.0f、.512(0.512 可以省略 0)

                科学计数法形式:如:5.12e2、5.12E-2

        

        开发中用到浮点型数字,建议使用double型,如精度要求更高可以使用long double 型。

(2)字面量后缀

  1. 浮点数字面量默认是double型,
  2. 如果需要表示float类型字面量,须加后缀 f 或 F。
  3. 如果需要表示long double类型字面量,需加后缀 l 或 L。

 (3)格式占位符

        在C语言中,占位符是一种用于格式化输出的特殊字符,通常用于 printf() 等输出函数中,用于指定输出的格式和内容。

  1. %f 是浮点类型的格式占位符,在printf中对应double类型(float类型会转换成double来处理);默认会保留6位小数,可以指定小数位数,如:%.2f 表示保留2位小数。
  2. %lf在printf中和 %f意思相同(C99标准加入),也对应double类型,默认保留6位小数,可以指定小数位数,如:%.2lf 表示保留2位小数。但需要注意的是,在scanf中 %lf和 %f含义不同:输入一个float类型数据时使用 %f;而输入double类型时必须使用 %lf。
  3. %Lf 对应的是long double 类型,默认保留6位小数,可以指定小数位数,如: %.2Lf 表示保留2位小数。需要注意的是,输入输出 long double 类型都必须使用 %Lf 占位符。
  4. %e 对应科学计数法表示的浮点数,可以指定尾数部分所保留的小数位数,如 %.2e 表示尾数部分保留两位小数
#include <stdio.h>

int main()
{
    // double 类型
    double a1 = 3.1415;
    double a2 = .12345678;
    double a3 = -2e12;
    double a4 = 1.9823e2;
    printf("a1=%f, a2=%.10f, a3=%.2lf, a4=%lf \n", a1, a2, a3, a4);
    printf("a1=%e, a2=%.2e, a3=%e, a4=%e \n", a1, a2, a3, a4);

    // float 类型
    float b1 = 3.1415f;
    float b2 = .123456f;
    float b3 = -2e12f;
    float b4 = 1.9823e2f;
    printf("b1=%f, b2=%f, b3=%.0f, b4=%f \n", b1, b2, b3, b4);
    printf("b1=%e, b2=%.2e, b3=%e, b4=%e \n\n", b1, b2, b3, b4);

    return 0;
}

 三:字符类型

        字符类型 char 可以表示单个字符,如一个数字、一个字母、一个符号。

        char类型的字面量是用单引号括起来的单个字符。

        可以使用转义字符 \ 表示特殊含义的字符。

转义字符

说明

\b

退格

\n

换行符

\r

回车符

\t

制表符

\”

双引号

\’

单引号

\\

反斜杠

        多个字符称为字符串,在C语言中使用char数组表示,数组不是基本数据类型,而是构造类型,我们后续专门讲解。

        使用%c表示char类型。

  1. C语言中,char类型本质是一个整数,是ASCII码中对应的数字,存储长度是 1 个字节,char类型也可以进行数学运算。
  2. 字符型同样分为signed char(无符号)和unsigned char(有符号),其中signed char取值范围-128 ~ 127,unsigned char取值范围0 ~ 255。默认是否带符号取决于当前运行环境。

(1)ASCII 码介绍

        ASCII(American Standard Code for Information Interchange)码是一种用于表示文本字符的字符编码标准,一共规定了128个字符的编码,比如空格“SPACE” 是32(二进制00100000),大写的字母A是65(二进制01000001)。

#include <stdio.h>

int main()
{
    // char 类型字面量需要使用单引号包裹
    char a1 = 'A';
    char a2 = '9';
    char a3 = '\t';
    printf("c1=%c, c3=%c, c2=%c \n", a1, a3, a2);

    // char 类型本质上整数可以进行运算
    char b1 = 'b';
    char b2 = 101;
    printf("%c->%d \n", b1, b1);
    printf("%c->%d \n", b2, b2);
    printf("%c+%c=%d \n", b1, b2, b1 + b2);

    // char 类型取值范围
    unsigned char c1 = 200; // 无符号char取值范围 0 ~255
    signed char c2 = 200;   // 有符号char取值范围 -128~127,c2会超出范围
    char c3 = 200;          // 当前系统,char 默认是 signed char
    printf("c1=%d, c2=%d, c3=%d", c1, c2, c3);

    return 0;
}

 四:布尔类型

        布尔值用于表示真、假两种状态,通常用于逻辑运算和条件判断。

        C89标准没有定义布尔类型,判断真假时以0为假,非0为真 ,但这种做法不直观,我们一般需要借助C语言的宏定义。

#include <stdio.h>

// 宏定义
#define BOOL int
#define TURE 1
#define FALSE 0

int main()
{
    // 使用整型表示真假两种状态
    // int isPass = 0;
    // int isOk = 1;

    // 借助于宏定义
    BOOL isPass = FALSE;
    BOOL isOk = TURE;

    printf("isPass=%d, isOk=%d \n", isPass, isOk);

    if (isPass)
    {
        printf("Pass");
    }

    if (isOk)
    {
        printf("Ok");
    }

    return 0;
}

        C99标准提供了_Bool 型,_Bool仍是整数类型,但与一般整型不同的是,_Bool变量只能赋值为0或1,非0的值都会被存储为1。

#include <stdio.h>

int main()
{
    // 使用 _BOOL 类型
    _Bool isPass = 0;
    //_Bool isOk = 1;
    _Bool isOk = -4;

    printf("isPass=%d, isOk=%d \n", isPass, isOk);

    if (isPass)
    {
        printf("Pass");
    }

    if (isOk)
    {
        printf("Ok");
    }

    return 0;
}

        C99标准还提供了一个头文件 <stdbool.h> 定义了bool代表_Bool,true代表1,false代表0。

#include <stdio.h>
#include <stdbool.h>

int main()
{
    bool isPass = false;
    bool isOk = true;

    printf("isPass=%d, isOk=%d \n", isPass, isOk);

    if (isPass)
    {
        printf("Pass");
    }

    if (isOk)
    {
        printf("Ok");
    }

    return 0;
}

五:获取数据的存储大小

        

        使用sizeof 可以获取数据类型或变量、字面量的存储大小,单位是字节。sizeof返回一个size_t类型的无符号整数值,格式占位符是 %zu。

        size_t 通常是 unsigned int 或 unsigned long 的别名,具体是哪个类型的别名,由系统和编译器决定。

        示例代码:

#include <stdio.h>

int main()
{
    // 计算数据类型的大小, 必须使用括号将数据类型关键字包裹起来
    printf("char:%zu \n", sizeof(char));               // char:1
    printf("short:%zu \n", sizeof(short));             // short:2
    printf("int:%zu \n", sizeof(int));                 // int:4
    printf("long:%zu \n", sizeof(long));               // long:4
    printf("long long:%zu \n", sizeof(long long));     // long long:8
    printf("float:%zu \n", sizeof(float));             // float:4
    printf("double:%zu \n", sizeof(double));           // double:8
    printf("long double:%zu \n", sizeof(long double)); // long double:16
    printf("\n");

    // 计算字面量数据的大小,字面量可以省略括号
    printf("%zu \n", sizeof('a')); // 4
    printf("%zu \n", sizeof(431)); // 4
    printf("%zu \n", sizeof 4.31); // 8
    printf("\n");

    // 计算变量的大小,变量可以省略括号
    char a = 'A';
    int b = 90;
    long long c = 100;
    double d = 10.8;
    printf("a: %zu \n", sizeof(a)); // a: 1
    printf("b: %zu \n", sizeof b);  // b: 4
    printf("c: %zu \n", sizeof(c)); // c: 8
    printf("d: %zu \n", sizeof(d)); // d: 8

    return 0;
}

六:数据类型转换

(1)自动类型转换(隐式转换)

        不同类型的数据进行混合运算,会发生数据类型转换,窄类型会自动转为宽类型,这样不会造成精度损失。

  1. 不同类型整数进行运算,窄类型整数自动转换为宽类型整数。
  2. 不同类型浮点数进行运算,精度小的类型自动转换为精度大的类型。
  3. 整数与浮点数进行运算,整数自动转换为浮点数。
#include <stdio.h>

int main()
{
    // 整型提升
    short s1 = 10;
    int n1 = 40000;
    // 运算过程中,变量 s1 是 short 类型,会自动转为 int 类型
    printf("%d \n", s1 + n1);

    // 有符号整数自动转为无符号整数
    // int n2 = 100;
    int n2 = -100;
    unsigned int n3 = 20;
    // 负数转为无符号整数,两者绝对值的和是无符号整数的最大值再加 1
    printf("%u \n", n2 + n3);

    // 不同类型的浮点数运算,精度低的转诶精度高的
    float f1 = 1.25f;
    double d2 = 4.58667435;
    // printf("%f \t", f1);
    printf("%.10f\n", f1 + d2);

    // 整型与浮点型运算,整型转为浮点型
    int n4 = 10;
    double d3 = 1.67;
    printf("%f", n4 + d3);

    return 0;
}

 (2)赋值时的自动类型转换

        在赋值运算中,赋值号两边量的数据类型不同时,等号右边的类型将转换为左边的类型。 如果窄类型赋值给宽类型,不会造成精度损失;如果宽类型赋值给窄类型,会造成精度损失。

#include <stdio.h>

int main()
{
    // 赋值 窄类型赋值给宽类型
    int a1 = 10;
    double a2 = a1;
    printf("%f \n", a2);

    // 赋值 宽类型赋值给窄类型
    double b1 = 1.2;
    int b2 = b1;
    printf("%d", b2);

    return 0;
}

(3)​​​​​​​强制类型转换(显式转换)

        隐式类型转换中的宽类型赋值给窄类型,编译器是会产生警告的,提示程序存在潜在的隐患,如果非常明确地希望转换数据类型,就需要用到强制(或显式)类型转换。

(类型名)变量、常量或表达式

#include <stdio.h>

int main()
{
    double d1 = 1.934;
    double d2 = 4.2;
    int num1 = (int)d1 + (int)d2;         // d1转为1,d2转为4,结果是5
    int num2 = (int)(d1 + d2);            // d1+d2=6.134,6.134转为6
    int num3 = (int)(3.5 * 10 + 6 * 1.5); // 35.0 + 9.0 = 44.0 -> int = 44

    printf("num1=%d \n", num1);
    printf("num2=%d \n", num2);
    printf("num3=%d \n", num3);

    return 0;
}

        本章的内容就到这里。

        关注我一起成为嵌入式大佬。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值