learn_C_deep_4 (类型和变量命名、sizeof(int) *p表示什么意思、原码、反码和补码的概念、计算机中数据计算时,为什么要转为二级制、unsigned和signed关键字)

简介: learn_C_deep_4 (类型和变量命名、sizeof(int) *p表示什么意思、原码、反码和补码的概念、计算机中数据计算时,为什么要转为二级制、unsigned和signed关键字)

类型和变量命名


C语言为什么要有类型


类型是编程语言中一项非常基础的概念。它是用来描述数据的种类或数据类型的,可以是基本类型,如整数、浮点数、字符等,也可以是由基本类型组成的复合类型,如数组、结构体等。类型的存在有以下几个作用:


1. 内存分配:不同类型的数据需要占用不同大小的内存空间,类型可以告诉编译器为变量分配多大的内存空间。

2. 数据验证:类型可以帮助编译器验证数据的完整性和正确性。例如,如果一个变量被声明为整数类型,那么它就只能存储整数值,如果我们试图将它赋值为字符串或其他数据类型,编译器就会给出错误提示。

3. 数据处理:不同类型的数据有着不同的处理方式,例如整数和浮点数的运算方式就是不同的。因此类型可以告知编译器对数据进行何种运算或操作。

总之,类型让程序员可以更加准确地控制和处理数据。同时,类型也可以帮助编译器在编译时进行静态类型检查,防止一些错误在运行时才被发现,提高程序的可靠性和稳定性。


为什么又有那么多种数据类型


C语言有这么多不同的数据类型,是为了满足不同的需求,更确切地表示各种不同类型的数据。不同的数据类型在存储数据时占用不同的内存空间,也有不同的精度和范围,因此程序员需要根据具体的情况来选择合适的数据类型。

例如,在需要存储一个整数时,如果使用char类型,虽然它能够存储整数,但是它只能够存储非常小的整数,如果需要存储较大的整数,就需要使用int类型或long类型。同样的道理,如果需要存储小数,就需要使用float类型或double类型,因为它们具有更高的精度。

此外,不同的数据类型在编写程序时也有不同的用途。例如,指针类型用于动态内存管理,结构体类型用于组织复杂的数据,枚举类型用于在程序中定义特定的常量等等。


变量的命名规则


在C语言中,变量的命名必须遵循以下规则:


1. 变量名只能由字母、数字和下划线组成,不能使用其他符号。

2. 变量名必须以字母或下划线开头。

3. 变量名不能使用C语言中的关键字(例如,if、for、while等)。

4. 变量名的长度没有限制,但在实际编程中,建议将变量名控制在20个字符以内,以方便阅读和维护。

5. 变量名区分大小写,因此,变量名abc和ABC是不同的变量。

6. 变量名应该选择有意义的名称,能够清晰地反映变量的含义。


变量的命名规范


1. 使用有意义的变量名:应该使用能够清楚反映变量含义的名称,例如,使用count来表示计数器变量。

2. 使用小写字母:建议使用小写字母来表示变量名。这种命名方式更容易阅读和维护代码。 3. 使用驼峰命名法:对于由多个单词组成的变量名,可以使用驼峰命名法来表示,即第一个单词以小写字母开始,后续单词的首字母大写。例如,可以使用studentName来表示学生姓名。

4. 不要使用缩写和简写:尽量避免使用缩写和简写来表示变量名。这样的命名方式很容易引起歧义,降低代码的可读性。

5. 避免使用数字开头:变量名不能以数字开头,因为在C语言中,数字开头的名称会被解释为常量。

6. 使用下划线作为单词之间的分隔符:在驼峰命名法中,需要使用下划线作为单词之间的分隔符。例如,student_name。

7. 注意命名空间:变量名应该跟变量所属的函数相关,避免命名冲突。

8.使用"g_"或 "s_"前缀:建议在全局变量名前加上"g_"或 "s_"前缀,以便区别于局部变量。其中,"g_"表示全局变量,"s_"表示静态全局变量。

9.所有的宏定义、枚举常量、只读变量全用大写字母命名,用下划线线分割。


定义变量一定要初始化


#include<stdio.h>
int main()
{
  int a;
  printf("%d", a);
  //vs编译器直接禁止使用未初始化的变量
  //error C4700: 使用了未初始化的局部变量“a”
  return 0;
}


  如果您声明了一个局部变量但没有初始化它,那么这个变量的初始值将是未定义的,并且其内容可能是任意值。打印未初始化的变量的值是一种不确定行为,因为其内容是不确定的,可能会有垃圾值、0或其他值。


sizeof(int) *p表示什么意思


       继上章的sizeof关键字,我们接着来讲解sizeof关键字,先回忆回忆sizeof是干嘛的

#include<stdio.h>
int main()
{
  int* p = NULL; //声明一个指向整型变量的指针,赋初值为NULL。
  int arr[10]; //声明一个包含10个整型变量的数组。
  int* test[3]; //声明一个包含3个指向整型变量的指针数组。
  printf("%d\n", sizeof(p));//4
  printf("%d\n", sizeof(arr));//40
  printf("%d\n", sizeof(test));//12
  return 0;
}


`sizeof`是C和C++中的一个操作符,用于获取其操作数(变量、类型、表达式等)的字节大小。


那么现在来解释一下sizeof(int) *p表示什么意思。


`sizeof(int)`是一个求整型变量大小的操作符,它返回类型`int`在内存中占据的字节数。通常情况下,一个`int`类型变量占据4个字节(32位系统)或者8个字节(64位系统),具体取决于编译器和操作系统的实现。

`*p`是指针运算符,用来访问指针所指向的内存地址处的值。`p`是一个指向某个整型变量的指针。

因此,`sizeof(int) *p`表示用一个指向整型变量的指针`p`存储一个整型变量的大小。因为一个`int`类型变量通常占据4个字节,所以这条语句等价于`4 *p`。

注意,`sizeof`是一个关键字,而不是函数,不需要用括号将它的参数括起来。在这个例子中,括号会被认为是指向一个函数的指针,而不是求类型大小的操作符。因此,正确的写法应该是`sizeof(int) * p`。


原码、反码和补码的概念


原码(Sign-Magnitude):原码是二进制表示有符号整数的最简单方式,它的表示方法就是使用二进制数,最高位表示符号位,0表示正数,1表示负数。例如,+5的原码为00000101,-5的原码为10000101。原码的优点是简单直观,易于理解,但是存在着符号位和数值位的处理不一致的问题。


反码(One's Complement):反码是在原码的基础上,为了解决符号位和数值位处理不一致的问题而设计的。对于正数,其反码就是其原码本身;对于负数,反码的符号位一定是1,数值部分则取原码的数值部分按位取反(0变成1,1变成0),得到的二进制码就是该负数的反码表示。例如,+5的反码为00000101,-5的反码为11111010。反码的优点是对于数值部分的计算仍然是直接相加,但是符号位仍需要额外判断。


补码(Two's Complement):补码是在反码的基础上,为了解决符号位和数值位处理不一致的问题而产生的。补码表示负数时,先将其转换为其反码,再将反码加1得到补码;补码表示正数时,与原码一样。例如,+5的补码为00000101,-5的补码为11111011。补码的优点在于符号位的处理与数值位的处理是统一的,不需要特殊处理。在补码的表示方式下,负数的补码是它的绝对值的原码按位取反再加1,正数的补码和原码一样。


       总的来说,原码、反码和补码都是表示整数的方法,但是它们对于负数的处理方式不同,补码是最常用的表示方法,也是计算机中进行加减运算时的默认方式,因为补码可以实现符号位和数值位的统一处理,同时在计算机中进行加减运算时也非常方便。


计算机中数据计算时,为什么要转为二级制


       二进制是一种只包含二个数字(0和1)的进制,这种进制可以用来表示所有数字、文字、图形等。而计算机中的所有操作都是由电子元器件完成的,这些元器件只能表示两种状态(电信号的通/断状态),即0和1,所以在计算机中使用二进制可以更直接地与硬件电路之间进行交互。具体来说,计算机将二进制位串(由一系列0和1组成的序列)转换为数字、文字、图形等,进行处理后再将其转换为二进制位串储存到计算机存储器中,在需要时再将其读取并进行相应的操作,最后再将其转换为人类可读的形式输出。这种转换过程虽然看似繁琐,但是计算机中的各种运算、逻辑判断、图像处理等操作都是以二进制数值形式进行的,因此转换为二进制有助于计算机进行高效的运算和存储。所以任何数据在计算中中,都必须转为二级制。


unsigned和signed关键字


unsigned和signed关键字的理解


       在计算机中,整数类型的表示和存储通常是通过二进制补码来完成的。对于有符号整数类型(即signed类型),最高位是符号位,0表示正数,1表示负数。如果要表示-1这个数,需要使用二进制补码来表示,即将1的二进制码取反(变成0),再加1,得到11111111(表示-1的补码),正数的原反补码相同。


而对于无符号整数类型(即unsigned类型),没有符号位,其所有二进制位都表示数值,最小值为0。其原反补码都相同,因此,对于unsigned类型的整数,它只能表示非负整数,而无法表示负数。


因为signed和unsigned类型的表示方式不同,所以它们在使用时需要注意:


1. 范围不同:带符号类型能够表示的整数范围是从负的最大值到正的最大值,而无符号类型只能表示从0到正的最大值。

2. 溢出问题:在进行运算时,如果signed类型的值超过了其范围,会出现溢出现象。而unsigned类型的值超过了其范围,则会进行“回绕”,即从最小值重新开始。

3. 运算方式不同:在进行运算时,signed类型和unsigned类型的运算方式也有所不同。比如,在进行位运算时,signed类型的值会进行符号扩展,而unsigned类型的值则会进行零扩展。


计算二进制的便捷方法 - 2^n


#include<stdio.h>
int main()
{
  //计算机内存储的整形必须是补码
  int a = 10;
  //任何数据在计算中中,都必须转为二级制
  //符号位(0,1) + 数据位
  //有符号正数,原反补码相同
  //0000 0000 0000 0000 0000 0000 0000 1010 - 原码、反码、补码
  //16进制
  //0x00 00 00 0a
  int b = -20;
  //16+4 16 = 2^4   4 = 2^2
  //2^n次方 二级制1后面就有n个0
  //16 = 2^4  10000
  //4 = 2^2   00100
  //         相加
  //因为-20是负数 int - 4字节 - 32位
  //最高位是符号位 - 负数 - 1
  //1000 0000 0000 0000 0000 0000 0001 0100 - 原码
  //1111 1111 1111 1111 1111 1111 1110 1011 - 反码,符号位不变,其他按位取反
  //1111 1111 1111 1111 1111 1111 1110 1100 - 补码,反码加1
  //16进制
  //0xff ff ff ec
  return 0;
}


计算补码的方法


计算补码的方法如下:


1. 对于正数,其原码、反码和补码相同。

2. 对于负数,先求其绝对值的二进制表示的反码(即除符号位外的各位取反),然后再将其反码加1得到其补码。


例如,假设要求-5的补码,步骤如下:


       1. 5的二进制表示为0000 0101,因为是正数,所以补码、反码和原码都相同,都是0000 0101。

       2. 将其转换为负数,即符号位变为1,得到1000 0101。

       3. 除符号位外的各位取反,得到1111 1010,这就是-5的反码。

       4. 将反码加1,得到1111 1011,这就是-5的补码。


因此,-5的补码是1111 1011。需要注意的是,在计算机中,通常采用补码表示有符号整数,这样可以避免加减法、逻辑运算等操作的特殊处理。


计算原码的方法


原码是一种二进制数的表示方法,符号位为0表示正数,为1表示负数。计算原码的方法如下:


1. 对于正数,直接将其转换为二进制数即可得到原码。

2. 对于负数,先将其转换成绝对值的二进制数,然后将该二进制数的每个位取反(0变成1,1变成0),最后再将符号位变成1即可得到原码。

3.通过补码求原码


3.1.-20的补码 -> 原码    

方法一:
1111 1111 1111 1111 1111 1111 1110 1100 - 补码 
1111 1111 1111 1111 1111 1111 1110 1011 - 反码 = 补码 - 1
1000 0000 0000 0000 0000 0000 0001 0100 - 原码 = 反码按位取反,符号位不变

3.2.-20的补码 -> 原码  

方法二:
1111 1111 1111 1111 1111 1111 1110 1100 - 原码
1000 0000 0000 0000 0000 0000 0001 0011 - 反码,符号位不变,其他按位取反
1000 0000 0000 0000 0000 0000 0001 0100 - 补码,反码加1


将上面的10和-20的补码转为16进制分别是0x00 00 00 0a和0xff ff ff ec,那我们再来看看它在计算机的内存是怎么存储的。


但是我们发现和我们计算的十六进制有一些区别,计算机的顺序好像是到过来的,这里我们就需要了解计算机存储数据的方式 - 大小端


大小端概念


       大小端(Endianness)是用于描述不同类型的计算机中多字节数据的存储方式。简单来说就是指定了大字节和小字节的存储顺序。一个字节通常由8个二进制位组成,而多字节数据是由多个字节组成的。在存储多字节数据时,我们需要确定这些字节在内存中的排列顺序。 具体来说,大端模式(Big Endian)是将最高有效位存放在最低的内存地址,而小端模式(Little Endian)则是将最低有效位存放在最低的内存地址。在大端模式中,字节序列的存储顺序与它们在数值序列中的顺序一致;而在小端模式中,字节序列的存储顺序与它们在数值序列中的顺序相反。 例如,十六进制值为0x12345678的32位整数,在大端模式中的存储顺序为12 34 56 78,而在小端模式中的存储顺序为78 56 34 12。 不同的处理器和操作系统使用的大小端模式可能不同,因此在进行数据交换和传输时,需要注意其大小端模式的差异。


所以我们刚刚求解的十六进制是大端模式,而我们的电脑存储数据的方式是小端模式。


反码在进行+1的操作时候,符号位也是要参与运行的


接下来我们看一下下面的代码是否正确


#include<stdio.h>

int main()

{

   unsigned int a = 10;//right

   unsigned int b = -10;//?


   //编译不报错

   return 0;

}

       在这个代码中,将-10赋值给了unsigned int类型的变量b。由于unsigned int是无符号整型,它的取值范围是0~4294967295,因此b实际上存储的是4294967286,这是-10的补码在无符号整型范围内的表示。

相关实践学习
简单用户画像分析
本场景主要介绍基于海量日志数据进行简单用户画像分析为背景,如何通过使用DataWorks完成数据采集 、加工数据、配置数据质量监控和数据可视化展现等任务。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps&nbsp;
相关文章
|
1月前
|
数据采集 分布式计算 数据处理
Dataphin常见问题之与指定类型int不兼容如何解决
Dataphin是阿里云提供的一站式数据处理服务,旨在帮助企业构建一体化的智能数据处理平台。Dataphin整合了数据建模、数据处理、数据开发、数据服务等多个功能,支持企业更高效地进行数据治理和分析。
|
1月前
|
安全 编译器 Go
Go语言中的int和int32:同一个概念吗?
【2月更文挑战第24天】
62 3
|
1月前
|
SQL 流计算 OceanBase
OceanBase CDC从热OB库采集过来的Tinyint(1)类型会默认转换成Boolean,请教一下,如果想转换成int类型,有什方法么?
【2月更文挑战第25天】OceanBase CDC从热OB库采集过来的Tinyint(1)类型会默认转换成Boolean,请教一下,如果想转换成int类型,有什方法么?
28 3
|
1月前
|
Python
Python系列(15)—— int类型转string类型
Python系列(15)—— int类型转string类型
|
1月前
|
存储 编译器 C语言
c语言中int的作用和类型
c语言中int的作用和类型
27 0
|
3月前
|
存储 人工智能 编译器
learn_C_deep_5 (温故知新、sigend char a = -128的深度理解、unsigned int类型的写法规范)
learn_C_deep_5 (温故知新、sigend char a = -128的深度理解、unsigned int类型的写法规范)
|
3月前
|
存储 C语言
学习总结(位操作符;循环输入的三种方式;交换两个变量值的三种方法;打印数字对应的二进制;unsigned int 与int 的区别;改变特定位数0/1;&&和||的连续操作(与前置,后置结合))
学习总结(位操作符;循环输入的三种方式;交换两个变量值的三种方法;打印数字对应的二进制;unsigned int 与int 的区别;改变特定位数0/1;&&和||的连续操作(与前置,后置结合))
32 0
|
4月前
|
分布式计算 大数据 MaxCompute
大数据计算MaxCompute表字段a为string类型,里面存的数据格式为小数, 通过alter table是不能将这个字段a转为decimal类型吗?
大数据计算MaxCompute表字段a为string类型,里面存的数据格式为小数, 通过alter table是不能将这个字段a转为decimal类型吗?
39 0
|
4月前
|
SQL 分布式计算 大数据
大数据计算MaxCompute表字段a为string类型,里面存的数据格式为小数, 通过alter table是不能将这个字段a转为decimal类型吗?
大数据计算MaxCompute表字段a为string类型,里面存的数据格式为小数, 通过alter table是不能将这个字段a转为decimal类型吗?
51 0
|
4月前
|
存储 SQL 分布式计算
请问大数据计算MaxCompute建表时怎么给decimal类型的字段设置默认值为0?
请问大数据计算MaxCompute建表时怎么给decimal类型的字段设置默认值为0?
52 0

热门文章

最新文章