【C语言】数据以及位运算

简介: 【C语言】数据以及位运算

C语言中数据的表示方法

各种数据类型可表示的数值范围

C语言编译器在<limits.h>头文件中以宏定义的形式定义了字符型以及其他整型所能表示的数值的最大值和最小值。

下面来看看在VC++环境下的各数据类型所能表示的数值范围。

  #include <stdio.h>
#include <limits.h>
int main(void)
{
  puts("该环境下各字符型、整型数值的范围:");
  printf("char              :%d~%d\n",CHAR_MIN,CHAR_MAX);
  printf("signed char       :%d~%d\n",SCHAR_MIN,SCHAR_MAX);
  printf("unsigned char     :%d~%d\n",0,UCHAR_MAX);
  printf("short             :%d~%d\n",SHRT_MIN,SHRT_MAX);
  printf("int               :%d~%d\n",INT_MIN,INT_MAX);
  printf("long              :%d~%d\n",LONG_MIN,LONG_MAX);
  printf("unsigned short    :%d~%d\n",0,USHRT_MAX);
  printf("unsigned int      :%u~%u\n",0,UINT_MAX);
  printf("unsigned long     :%lu~%lu\n",0,ULONG_MAX);
  return 0;
}

6302d697528e40ec97e35faf808b622b.png

位和CHAR_BIT

计算机中的所有数据都是用0和1(即“位”)的组合来表示的。

C语言中“位”(bit)的定义如下:

  • “位”是具有大量内存空间的运行环境的数据存储单元,可保存具有两种取值的对象。
  • “位”可取两种值,其中一种是0。将位设为0以外的值,称为“设置位”。

根据编译器的不同,char型在内存上占据的位数也不同。该位数作为对象式宏CHAR_BIT定义在<limits.h>中。

char型的位数因编译器而定,至少为8

能够用字符型表示的数值范围是依附于CHAR_BIT的。

#include <stdio.h>
#include <limits.h>
int main(void)
{
  printf("char 型在内存上占据的位数:%d\n",CHAR_BIT);
  return 0;
}

d18ece449f5b4167bac1ff442560d61f.png

char型的内部:

sizeof运算符

C语言中将表示字符的char型的长度定义为1。(char的长度可以通过计算机硬件的位数来确定。在32位系统中,char占用1个字节(8位);在64位系统中,char也仍然占用1个字节(8位)。这意味着char的长度不会随着计算机系统的升级而改变。)

通过使用sizeof运算符(sizeof operator),可以判断出包括chai型在内的所有数据类型的长度。该运算符以字节(bite)为单位。

下面我们来使用sizeof运算符,显示字符型和整型的长度。

#include <stdio.h>
int main(void)
{
  printf("sizeof(char)=%d\n",sizeof(char));
  printf("sizeof(short)=%d\n",sizeof(short));
  printf("sizeof(int)=%d\n",sizeof(int));
  printf("sizeof(long)=%d\n",sizeof(long));
  printf("sizeof(unsigned char)=%u\n",(unsigned)sizeof(char));
  printf("sizeof(unsigned short)=%u\n",(unsigned)sizeof(short));
  printf("sizeof(unsigned int)=%u\n",(unsigned)sizeof(int));
  printf("sizeof(unsigned long)=%u\n",(unsigned)sizeof(long));
  return 0;
}

2de65ab817b64cfcb382fbdc7b6e182f.png

程序的运行结果因编译器和编译环境的不同而不同。但sizeof(char)必为1。`

各种数据类型的有符号型和无符号型的长度相同。例如,sizeof(short)和sizeof(unsigned short)相等,sizeof(long)和sizeof(unsigned long)相等。

  • short 、int、long具有如下关系:
    sizeof(short)≤sizeof(int)≤sizeof(long)
    即右侧的数据类型和左侧的数据类型相等,或者大于左侧的数据类型。

整型的内部表示

整型内部的位表示使用的是纯二进制计数法(pure binary numeration system)。但对于构成整型的位序列的解释,无符号类型有符号类型是完全不同的。

无符号整数的内部表示

无符号整数的数值在计算机内部是以二进制数来表示的,该二进制数与各二进制位一一对应。例如十进制数25用二进制数表示如下:

25用二进制数表示是11001,高位补0后表示为0000000000011001。

以16位为例,无符号整数的最小值为0,即0000 0000 0000 0000,最大值为65535,即1111 1111 1111 1111。


有符号整数的内部表示

当存储有符号数时,最高位为符号位(1表示负数,0表示非负数),其余位是数据位

计算机中有符号整数的存储是以补码形式存储的。

一个整数有以下三种编码。

原码

十进制整数数码化为原码的方法是首先把十进制整数转换为二进制,然后在高位用0补足15位,最后添上符号位。

反码

对整数而言,原码即为反码,对负数而言,反码是将原码中除符号位之外的其余位依次取反。

补码

对整数而言,原码即为补码。对负数而言,补码是在反码的基础上加1。在求补码的过程中,符号位不发生变化,当数据的最高位有进位时,舍弃进位。

补码的运算法则如下:

位运算

位运算符

C语言提供了六种运算符:

&位与运算符

|位或运算符

^位异或运算符

~位取反运算符(单目运算符)

<<位左移运算符

>>位右移运算符

注意,位运算的对象只能是整型和字符型,不能是浮点型数据。运算结果是整形数据。

位与运算

&运算的含义是对参与运算的两个运算对象的机器码按二进制方式对相应位进行位与运算,当两个相应位都为1时,运算结果的相应位也为1;否则,运算结果的相应位为0。


位或运算

|运算的含义是对参与运算的两个运算对象的机器码按二进制方式对相应位进行位或运算,当两个相应位都为0时,运算结果的相应位也为0,否则运算结果的相应位为1。

位异或运算

^运算的含义是对参与运算的两个运算对象的机器码按二进制方式对相应位进行位异或运算,当两个相应位相同时,运算结果的相应位为0,否则运算结果的相应位为1。

位取反运算

运算的含义是对参与运算的运算对象的机器码按二进制方式对相应位进行位取反运算,1变0,0变1。

注: &|运算符的功能和&&||!运算符功能相似,但要注意它们的区别。

&&||!会根据非零为真,零为假的运算规则对操作数进行逻辑运算。

&|会根据1为真,0为假的运算规则对操作数的二进制位进行逻辑运算。

例如:

表达式 3 & -1的值计算如下:


而表达式 3 && -1的值为1.

位左移运算符

<<运算的含义是对参与运算的运算对象的机器码按规定的移位数进行左移。<<运算符构成的表达式一般格式为a<<n,其中a是需要移位的数据,n是移位的位数。在移位的过程中,高位移除的位舍弃,低位左移后补0。

例如:

表达式a<<1的运算如下:(a=3)


这里需要注意的是,a<<1后,a的值不变。

以上述为例,通过左移a<<1的值为6,是原来的2倍。其实不难理解,以十进指数为例,假如将198进行左移,低位补0后,变成了1980,是原来的10倍。而在二进制中,若向左移动n位,那么a<<n就会变成原来的2的n次方。

位右移运算符

>>运算的含义是对参与运算的运算对象的机器码按规定的移位数进行右移。>>运算符构成的表达式一般格式为a>>n,其中a是需要移位的数据,n是移位的位数。

例如:

表达式a>>1(a=3)的运算如下:

同样的,a>>1后,a的值不变。

通过右移,a>>1的值变为原来的二分之一。在二进制中,若向右移动n位,则会变为2的n次方分之一。(不一定是恰好是整数倍,可能会有余数,但是商的结果是。)

逻辑位移与算术位移

对于右位移运算,可以分为两种,逻辑位移和算术位移。

逻辑位移

逻辑移位不考虑符号位,所有二进制位都进行位移。(包含符号位在内的所有位都进行位移)

这样对于负数而言,进行右位移运算后,会变成非负数。

例b>>4(b=-16)

位移为-16,进行位移运算,b>>4的值为2的12次-1。

算术位移

算术位移会保留最高位的符号位,只对除了符号位之外的其他位进行位移。

对于位移之后的空位用符号位的值进行填充。位移前后的符号不变,即负数还是负数,正数还是非负数。

以上述b>>4(b=16)为例

b>>4的值为-1。

相关文章
|
10月前
|
存储 程序员 编译器
C 语言中的数据类型转换:连接不同数据世界的桥梁
C语言中的数据类型转换是程序设计中不可或缺的一部分,它如同连接不同数据世界的桥梁,使得不同类型的变量之间能够互相传递和转换,确保了程序的灵活性与兼容性。通过强制类型转换或自动类型转换,C语言允许开发者在保证数据完整性的前提下,实现复杂的数据处理逻辑。
|
11月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
417 1
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
822 0
|
10月前
|
存储 数据管理 C语言
C 语言中的文件操作:数据持久化的关键桥梁
C语言中的文件操作是实现数据持久化的重要手段,通过 fopen、fclose、fread、fwrite 等函数,可以实现对文件的创建、读写和关闭,构建程序与外部数据存储之间的桥梁。
|
10月前
|
存储 算法 安全
C 语言中的位运算:挖掘底层计算的高效力量
位运算是C语言中直接操作二进制位的一种技术,能高效处理底层数据,广泛应用于优化算法、硬件编程等领域,是掌握C语言高级特性的关键之一。
|
11月前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
328 12
|
11月前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
12月前
|
存储 C语言 C++
深入C语言,发现多样的数据之枚举和联合体
深入C语言,发现多样的数据之枚举和联合体
125 0
深入C语言,发现多样的数据之枚举和联合体
|
存储 C语言
C语言程序设计核心详解 第十章:位运算和c语言文件操作详解_文件操作函数
本文详细介绍了C语言中的位运算和文件操作。位运算包括按位与、或、异或、取反、左移和右移等六种运算符及其复合赋值运算符,每种运算符的功能和应用场景都有具体说明。文件操作部分则涵盖了文件的概念、分类、文件类型指针、文件的打开与关闭、读写操作及当前读写位置的调整等内容,提供了丰富的示例帮助理解。通过对本文的学习,读者可以全面掌握C语言中的位运算和文件处理技术。
169 5
|
C语言
C语言程序设计核心详解 第二章:数据与数据类型 4种常量详解 常见表达式详解
本文详细介绍了C语言中的数据与数据类型,包括常量、变量、表达式和函数等内容。常量分为整型、实型、字符型和字符串常量,其中整型常量有十进制、八进制和十六进制三种形式;实型常量包括小数和指数形式;字符型常量涵盖常规字符、转义字符及八进制、十六进制形式;字符串常量由双引号括起。变量遵循先定义后使用的规则,并需遵守命名规范。函数分为标准函数和自定义函数,如`sqrt()`和`abs()`。表达式涉及算术、赋值、自增自减和逗号运算符等,需注意运算符的优先级和结合性。文章还介绍了强制类型转换及隐式转换的概念。
289 2