掘根宝典之C语言基本数据类型详解1——整型介绍,整数溢出,大小端,整型常量的存储,整型提升

本文详细介绍了C语言中的基本数据类型,如int、short、long、longlong和char,探讨了不同类型的特点、存储方式、整数溢出现象(有符号和无符号)、以及大小端概念。强调了在编程时选择合适的数据类型和处理溢出的重要性。
摘要由CSDN通过智能技术生成

目录

基本数据类型的介绍

类型的意义 

修饰符类型:

 整型数据类型

int:

short int(通常写short):

long int(通常写long):

long long(通常写long long):

char

使用多种整数类型的原因 

整型常量的存储

1.字面常量:

2.后缀:

3.字节顺序:

字符常量的存储 

整数溢出

有符号整数溢出:

无符号整数溢出:

位操作整数溢出

危险实例:

大小端

高低位

高低地址

区分高低地址和高低位

小端字节序存储(Little Endian):

大端字节序存储·(Big Endian):

为什么会有大小端?

如何确定大小端?

共用体确定大小端

指针确定大小端 


基本数据类型的介绍

C语言中常见的数据类型有:

  • int(整型):用于表示整数,例如:int a = 10;
  • float(浮点型):用于表示小数,例如:float b = 3.14;
  • char(字符型):用于表示单个字符,例如:char c = 'A';
  • double(双精度浮点型):用于表示较大范围和精度的小数,例如:double d = 3.1415926;
  • void(无类型):通常用于函数的返回值类型,表示无返回值。

类型的意义 

1.使用这个类型开辟内存空间的大小(大小决定了使用范围)

2.编译器如何看待这内存空间存了什么(比如说int,编译器就认为这里面存了整数)

修饰符类型:

  • short(短整型):用于表示较小范围的整数,例如:short e = 100;
  • long(长整型):用于表示较大范围的整数,例如:long f = 100000;
  • unsigned(无符号类型):用于表示非负数,例如:unsigned int g = 10;
  • signed(有符号类型):用于表示有正负号的整数,例如:signed int h = -10;

 整型数据类型

c语言把不含小数点和指数的数作为整数。因此

C语言中的整型数据类型包括int、short、long和long long,实际上还包括char,bool

int:

大小:通常为4个字节,在32位系统中范围为-2,147,483,648(-2^31)到2,147,483,647(2^31-1)。

修饰符:signed(int默认为signed int)或unsigned。signed int  \  int可以表示正负整数,而unsigned int只能表示非负整数。

需要注意的是,int类型的大小可能会因为不同的编译器和操作系统而有所变化。因此,在编写程序时要考虑到这一点,以保证程序的可移植性。

short int(通常写short):

大小:通常为2个字节,在32位系统中范围为-32,768(-2^15到32,767。

修饰符:signed(short默认为signed short)或unsigned。signed short  \  short可以表示正负整数,而unsigned short只能表示非负整数。

long int(通常写long):

大小:通常为4个字节,在32位系统中范围与int相同,即-2,147,483,648到2,147,483,647。

修饰符:signed(long默认为signed long)或unsigned。

long long(通常写long long):

大小:通常为8个字节,在32位系统中范围为-9,223,372,036,854,775,808到9,223,372,036,854,775,807。

修饰符:signed(long long默认为signed long long)或unsigned。

注意:long至少要和int一样长,int至少要和short int一样长

bool

在C语言中,没有直接的bool类型,但可以使用stdbool.h头文件中定义的bool类型。在stdbool.h中,bool类型被定义为一个整数类型,只有两个值:true(非零值,通常是1)和false(零值)。所以bool类型实际上也是一种整数类型,通常为无符号int型,所占空间只要能存0或1即可可以通过#include <stdbool.h>来引用这个头文件并使用bool类型。

例如,可以这样声明一个bool类型的变量:

#include <stdbool.h>

int main() {
    bool isTrue = true;
    bool isFalse = false;

    return 0;
}

在上面的代码中,我们声明了两个bool类型的变量isTrue和isFalse,并分别赋予了true和false的值。需要注意的是,true和false只是该类型的两个取值,它们实际上是非零和零的简写。因此,可以将其他非零值(例如1)视为true,将零视为false。

此外,可以使用关系运算符(如==、!=、<、>等)和逻辑运算符(如&&、||、!等)来对bool类型的变量进行比较和操作。例如:

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

int main() {
    bool isTrue = true;
    bool isFalse = false;

    if (isTrue) {
        printf("isTrue is true\n");
    }

    if (!isFalse) {
        printf("isFalse is false\n");
    }

    return 0;
}

上面的代码中,使用if语句和逻辑非运算符来判断bool类型的变量isTrue和isFalse的值,并输出相应的结果。

char

C语言中的char用于存字符,但是从技术层面,char是整数类型。

char类型用于表示单个字符,本质是存储了该字符的ASCII码值(所以char也可以被视为整型,大小为-2^7到2^7-1)。它通常为1个字节大小。标准的ASCII码的范围是0-127,用char类型存储绰绰有余。

char类型可以用于表示字母、数字、标点符号和特殊字符等。每个字符都有一个对应的ASCII码值。

char ch; // 声明一个char变量
ch = 'A'; // 将字符常量赋值给变量
char ch = 'B'; // 声明并初始化char变量
 

char可以使用单引号将字符常量括起来。例如:'a'、'A'、'1'、'@'等。

char ch1 = 'A';
char ch2 = 'B';
int result = ch1 + ch2; // 字符相加,结果为整数
 

char类型还可以通过转义序列来表示特殊字符,如'\n'表示换行符,'\t'表示制表符。

char newline = '\n'; // 换行符
char tab = '\t'; // 制表符
char backslash = '\\'; // 反斜杠
 

char类型可以被赋值为整数,因为每个字符都有一个对应的ASCII码值。字符型变量也可以与整型变量进行运算。

char a=65;
printf("%c",a);//结果是A

需要注意的是,C语言中的char类型既可以被视为字符型数据类型,也可以被视为整型数据类型。这是因为char类型实际上是一个整数类型,它可以表示字符的ASCII码值。

#include <stdio.h>
    int main() {
        unsigned char d= 220;
        printf("%d",d);//结果是220
        return 0;
    }

实际上char也有signed char 和unsigned char,至于char是signed char 还是unsigned char,取决于编译器,因此我们需要将char变量控制在signed char和unsigned char的交集

使用多种整数类型的原因 

C语言提供了多种整数类型,主要是为了满足不同的需求和优化程序性能。下面是使用不同整数类型的一些常见原因:

  1. 空间优化:不同整数类型在存储空间上有不同的大小,选择合适的整数类型可以节省内存空间。例如,如果只需要存储0到255之间的整数,可以使用无符号字符型(unsigned char),它只需要1个字节的存储空间。

  2. 平台兼容性:不同的计算机体系结构和操作系统可能有不同的整数大小和范围限制。选择适当的整数类型可以保证程序在不同平台上的兼容性。

  3. 运算精度:某些类型的整数提供了更高的精度或更大的范围,以满足特定的数值计算需求。例如,长整型(long)提供了更大的范围,可以表示更大的整数值。

  4. 数据类型匹配:在处理某些特定数据或接口时,可能需要使用特定的整数类型以便与其他软件系统或硬件设备进行有效的数据交换。

  5. 优化性能:在某些情况下,使用较小的整数类型可以提高程序的性能。例如,使用无符号整数类型可以避免运行时的符号扩展操作,从而提高计算效率。

总之,选择适当的整数类型可以帮助提高程序的效率、节约内存,并保证程序的可移植性和兼容性。在选择整数类型时,需要根据具体的需求和特定的应用场景来做出合理的选择。

整型常量的存储

C语言中整数常量的存储方式取决于常量的值和类型。下面是一些常见的整数常量存储方式:

1.字面常量:

在源代码中直接写明的整数常量,如5、100、-10等,存储方式通常是根据常量的值和类型决定的。

c语言把十进制整数字面值存储为int,long,long long中尺寸中最小的那个,前提是要容纳的下当前的值。

八进制和十六进制整数字面值是能容纳其数值的int,unsigned int,long,unsigned long,long long和unsigned long long类型(前提是编译器能识别这些类型)当中的尺寸最小者

我们不免会在程序中使用整数常量,就像下面一样

1111111111111   /*编译器先将这个数存为int,发现不够大,
改存为long,发现还不够大,再改为long long*/

 例子

int a=10000000000000;

编译器将这个数字存为int,发现不够存,long ,再依次类推,直到存下这个数据的类型,假设这个数字被存为long,它被赋给int类型时就会直接截断成int类型的精度。 

2.后缀:

不过上面这样子一个个匹配类型的话会减慢程序运行速度,最好的做法就是直接指明整型常量的存储方式,我们就可以通过后缀来指定具体的类型

整数常量的存储方式还可以通过使用后缀来指定具体的类型。

常见的后缀包括u或者U表示无符号整数、l或者L表示长整数,ll或者LL表示长长整数。例如,常量10u表示无符号整数类型的10,常量1000000000l表示长整数类型的1000000000。

3.字节顺序:

对于占据多个字节的整数常量,存储方式还与字节顺序有关。通常采用的是小端字节顺序,即低位字节存储在低地址,高位字节存储在高地址。

我们后面会介绍

总之,整数常量的存储方式取决于常量的值和类型。编译器会根据常量的大小和后缀来选择合适的整数类型进行存储,同时也会根据字节顺序来存储多字节的整数常量。

字符常量的存储 

在c语言中,用单括号括起来的单个字符被称为字符常量。编译器一旦发现字符常量,就会将其转换未相应的ASCII码值并存储起来

整形提升

C语言中的整型提升是指在表达式中使用不同类型的整数时,会自动将较低精度的整数类型转换为较高精度的整数类型。

整型提升的规则如下:
1. 如果操作数中存在有符号和无符号整数,那么有符号整数会自动转换为无符号整数进行运算。
2. 如果操作数中存在不同大小的整数类型,那么小的整数类型会自动转换为大的整数类型进行运算。
3. 如果操作数中存在有符号整数和浮点数,那么有符号整数会自动转换为浮点数进行运算。
4. 如果操作数中存在不同大小的浮点数类型,那么小的浮点数类型会自动转换为大的浮点数类型进行运算。

整型提升的目的是为了避免数据丢失和提高运算精度。需要注意的是,整型提升只发生在运算符和赋值语句中,不会改变变量的类型。如果想要将提升后的整数类型赋值给原来的整数类型变量,需要进行强制类型转换。

例如,将一个signed char类型和一个int类型相加:

signed char a = 10;
int b = 20;
int c = a + b;

在这个例子中,signed char类型会被自动提升为int类型,然后进行相加运算。

整形提升可以避免数据丢失和不一致的问题,确保运算结果的正确性。但是需要注意的是,整形提升并不改变变量的实际类型,只是在表达式中临时提升为更高精度的类型。

整型常量存储和整型提升的实例

我们看个例子

char a=-1;

首先编译器把-1存为int类型:4字节,32比特位,原码是100……01(30个0),反码是111……110(31个1),补码为111……111(32个1);要将-1赋值给a,编译器就会自动截断,取前8位,即补码为11111111

printf("%d",a);

 %d为有符号整型,将一个char型转为int型打印,这就存在整型提升,即本来的补码为11111111整型提升为111……111(32个1);再将其转换为反码,原码,打印出来

整数溢出

我们知道每种数据类型都是有它的取值范围的,int的取值范围是-2^31到2^31-1,那如果我们用int类型存一个超出这个范围的值会怎么样呢?

下面是一些展示C语言整数溢出的示例:

有符号整数溢出:

#include <stdio.h>

int main() {
    int num = 2147483647;  // int类型最大值
    num = num + 1;  // 整数溢出
    printf("溢出后的值:%d\n", num);
    return 0;
}

输出结果: 溢出后的值:-2147483648

由于num已经达到了int类型的最大值,再加1就超过了它的表示范围,导致整数溢出。溢出后的值变成了-2147483648,即int类型的最小值。

事实上c标准没有定义有符号类型的溢出规则,以上描述的溢出行为比较具有代表性,但是也会出现其他情况

无符号整数溢出:

#include <stdio.h>

int main() {
    unsigned int num = 4294967295;  // unsigned int类型最大值
    num = num + 1;  // 无符号整数溢出
    printf("溢出后的值:%u\n", num);
    return 0;
}

输出结果: 溢出后的值:0

由于num已经达到了unsigned int类型的最大值,再加1就超过了它的表示范围,导致整数溢出。由于unsigned int类型没有负数表示,溢出后的值变成了0。

位操作整数溢出

下面是一个在位操作中导致整数溢出的例子:

#include <stdio.h>

int main() {
    unsigned int a = 1;
    unsigned int b = a << 32;  // 左移32位

    printf("b: %u\n", b);

    return 0;
}

在这个例子中,我们定义了一个无符号整数变量a,并将其左移32位赋值给变量b。根据C语言标准,对于一个32位的无符号整数,左移32位将导致整数溢出,结果是未定义的。

实际运行该程序时,输出结果可能是任意的,因为溢出后的行为是未定义的。在某些编译器上,可能会得到期望的结果0,但在其他编译器上,可能会得到不同的结果。这种结果的不确定性是因为溢出后的行为是未定义的,编译器可以自由选择溢出后的行为。因此,在位操作中使用正确的数据类型以及进行边界检查是非常重要的,以避免产生不确定的行为和潜在的错误。

危险实例:

#include <stdio.h>

int main() {
    unsigned char num ; 
    for(num=0;num<=255;num++)
    printf("%u\n", num);
    return 0;
}

我们会发现上面这个例子已经陷入了死循环

由于unsigned char类型的范围是0-255,在num为255的情况下加1会导致循环溢出,使得num的值变为0。

C语言中整数溢出的情况:

  1. 有符号整数溢出导致的未定义行为:当有符号整数溢出时,C语言标准规定这种情况会导致未定义行为。这意味着编译器不需要定义溢出后的行为,可能会产生任意的结果。例如,对于有符号整数类型int,当将其最大值加1时,它可能变成最小值,也可能导致未定义行为。

  2. 无符号整数溢出的模运算特性:对于无符号整数类型,溢出时会采用模运算的特性。例如,使用unsigned int类型,该类型的取值范围为0到4294967295。当达到最大值4294967295并再加1时,它将经过模运算,结果是0。这意味着溢出后的值将回到类型的最小值。

  3. 位操作中的整数溢出:在进行位操作时,如果操作数超过了数据类型的位宽度,会发生整数溢出。例如,对于unsigned int类型,其位宽度为32位。如果将其左移33位,将会发生整数溢出,结果是未定义的。

总体来说,C语言中的整数溢出是一个需要注意的问题。在编写代码时,应该特别关注使用有符号整数的情况,以及对无符号整数进行位操作的情况。为了避免整数溢出,应该合理选择适当的数据类型,并进行边界检查。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值