C语言详解关键字sizeof与unsigned及signed的用法

目录
  • 最冤枉的关键字sizeof理解
    • 被误解为函数
    • sizeof(int)*p 表示什么意思
  • signed与unsigned 关键字
    • 有符号整数vs无符号整数
    • 整形在内存的存储
      • 原码
      • 反码
      • 补码
      • 存储的本质
      • 十进制二进制快速转化
      • 为什么存储的是补码
      • 大小端

最冤枉的关键字sizeof理解

sizeof:确定一种类型在开辟空间的时候的大小。

被误解为函数

sizeof是关键字而不是函数,可以借助编译器来确定它的身份。

#include<stdio.h>
int main()
{
	int a = 10;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof a);
	printf("%d\n", sizeof int);//error
	return 0;
}

sizeof(a)可以去掉()说明sizeof不是函数,是关键字(操作符),因为函数后面的括号是不能省略的。

sizeof在计算变量所占的空间大小时,可以省略括号,而计算类型大小时,不能省略括号。

注:sizeof操作符里面不能有其他运算,否则达不到预期的结果。

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

#include<stdio.h>
int main()
{
	int* p = NULL;
	int arr[10] = { 0 };
	int* parr[3];
	printf("%d\n", sizeof(p));//p是指针变量,指针变量的大小是固定的4或者8
	printf("%d\n", sizeof(*p));//指针变量所指的变量所占的内存的大小
	printf("%d\n", sizeof(arr));//sizeof(arr)中arr指整个数组,即10个int类型元素。
	printf("%d\n", sizeof(arr[10]));//数组越界
	printf("%d\n", sizeof(&arr));//&arr取得是整个数组的地址
	printf("%d\n", sizeof(&arr[0]));//取的是首元素的地址,相当于指针
	printf("%d\n", sizeof(parr));//parr指整个数组。
	return 0;
}

指针变量p所指向的变量类型为char,指针数组parr中存储的指针变量的类型为char时候:

signed与unsigned 关键字

有符号整数vs无符号整数

char
 unsigned char//无符号的字符类型
 //取值范围是0~255
 //无符号表示二进制的最高位不表示正负,该整型只为正数。
 //但可以储存负数,只是值会变成很大的正数
 signed char//有符号字符
 //取值范围是-128~127
 //因为字符的本质是ASCII码值,在内存中以ASCII码值进行存储,所以划分到整型家族
short
 unsigned short [int]//无符号短整型
 signed short [int]//有符号短整型
int
 unsigned int//无符号整型
 signed int//有符号整型
long
 unsigned long [int]//无符号长整型
 signed long [int]//有符号整型
long long
 unsigned long long [int]//无符号更长的整型
 signed long long [int]  //有符号更长的整型

char到底是signed char (取值范围-128~127)还是unsigned char(取值范围0~255)

标准是为定义的,取决于编译器的实现,小沐所使用的VS2019环境的char是signed char。

char a;// signed char a 或者 unsigned char a

int 标准定义是 signed int ,有符号整型,4个字节,32个比特位

int a = 10;//signed int a
//转换成二进制是00000000000000000000000000001010

整形在内存的存储

一个变量的创建是要在内存中开辟空间的,空间的大小是根据不同的类型而决定的。

那么,数据在所开辟内存中到底是如何存储的呢?

计算机存储数值时时存储的该数值的二进制的补码的,而补码是通过原码和反码进行换算得到的。

任何数据在计算机中,都必须转换成二进制,计算机只认识二进制。

原码

直接将数值按照正负数的形式翻译成二进制就可以得到原码。

反码

将原码的符号位不变,其他位依次按位取反就可以得到反码。

补码

反码+1就得到补码。

int a = 10;
//00000000000000000000000000001010 a的原码
//00000000000000000000000000001010 a的反码
//00000000000000000000000000001010 a的补码
//0x0000000a
int b = -10;
//10000000000000000000000000001010 b的原码
//0x8000000a
//11111111111111111111111111110101 b的反码
//0xfffffff5
//11111111111111111111111111110110 b的补码
//0xfffffff6

符号位+数据位

有符号数且正数,原码,反码和补码相同。

有符号数且负数,原码,反码和补码不相同,需要通过计算转换。计算机内存储的整型必须是补码,符号位要参与计算的。

无符号数:没有符号位,原码,反码和补码相同。

int a = 20;

int b = -10;

我们知道,编译器为 a 分配四个字节的空间。那如何存储呢? 首先,对于有符号数,一定要能表示该数据是正数还是负数。所以我们一般用最高比特位来进行充当符号位。 原码、反码、补码 计算机中的有符号数有三种表示方法,即原码、反码和补码。 三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位三种表示方法各不相同。 如果一个数据是负数,那么就要遵守下面规则进行转化: 原码:直接将二进制按照正负数的形式翻译成二进制就可以。 反码:将原码的符号位不变,其他位依次按位取反就可以得到了。 补码:反码+1就得到补码。 如果一个数据是正数,那么它的原反补都相同。

无符号数:不需要转化,也不需要符号位,原反补相同。

对于整形来说:数据存放内存中其实存放的是补码。

//字面值转补码

int a = 20;

//20是正整数

//0000 0000 0000 0000 0000 0000 0001 0100

int b = -10;

//-10是正整数

//1000 0000 0000 0000 0000 0000 0000 1010

//1111 1111 1111 1111 1111 1111 1111 0101

//1111 1111 1111 1111 1111 1111 1111 0110

补码转原码

方法一:先-1,在符号位不变,按位取反。

方法二:将原码到补码的过程在来一遍。

原反补转换需要通过计算机硬件来完成,

可以使用一条硬件电路就能完成原反补码的转换。

存储的本质

#include<stdio.h>
int main()
{
	unsigned int a = -10;
	//1000 0000 0000 0000 0000 0000 0000 1010--  -10的原码
	//1111 1111 1111 1111 1111 1111 1111 0110--  -10的补码
	printf("%d\n", a);
	printf("%u\n", a);
	return 0;
}

无符号整型变量a定义时,先有空间,再有内容,先将内容转换成二进制。 整型再存储的时候,空间不关心内容的。

在将数据保存在空间内的时候,数据已经被转换成二进制的补码。

数据带上类型才有意义。类型觉得了如何解释空间内部保存的二进制序列。

变量的类型什么时候起效果?

在读取数据的过程中,变量的类型起效果。

//变量的存和取过程的结论:

//存:字面数据必须先转成补码,在放入空间当中。所以,所谓符号位,完全看数据本身是否携带±号。和变量是否有符号

无关!

//取:取数据一定要先看变量本身类型,然后才决定要不要看最高符号位。如果不需要,直接二进制转成十进制。如果需要,则需要转成原码,然后才能识别。(当然,最高符号位在哪里,又要明确大小端)

十进制二进制快速转化

口诀:1后面跟n个0,就是2的n次方

67->64++1-->2^6+2^1+2^0
0000 0000 0000 0000 0000 0000 00100 0011
1->2^0
10->2^1
100->2^2
1000->2^3
后面跟n给比特位就是2^n
2^9->1000000000

为什么存储的是补码

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;

同时,加法和减法也可以统一处理(CPU只有加法器)。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

大小端

什么大端小端:

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;

小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。

例如:

0x11223344

为什么有大端和小端:

因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8 bit。但是在C语言中除了8 bit的char之外,还有16 bit的short型,32 bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

例如:一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为高字节, 0x22 为低字节。对于大端模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。小端模式,刚好相反。我们常用的 X86 结构是小端模式,而 KEIL C51 则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

到此这篇关于C语言详解关键字sizeof与unsigned及signed的用法的文章就介绍到这了,更多相关C语言 sizeof unsigned signed内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解C语言中sizeof如何在自定义函数中正常工作

    1.在main函数中,sizeof是可以正常工作的,比如: int main() { int n[5]; printf("input: \n"); int i ; for(i = 0; i < 5; i++) { scanf("%d",n + i); } int len = sizeof(n)/sizeof(n[0]); printf("%d\n",len); return 0; } 2.但是在自定义函数中就不可以了,如下: #includ

  • 基于C语言char与unsigned char的区别介绍

    在C中,默认的基础数据类型均为signed,现在我们以char为例,说明(signed) char与unsigned char之间的区别. 首先在内存中,char与unsigned char没有什么不同,都是一个字节,唯一的区别是,char的最高位为符号位,因此char能表示-127~127,unsigned char没有符号位,因此能表示0~255,这个好理解,8个bit,最多256种情况,因此无论如何都能表示256个数字. 在实际使用过程种有什么区别呢?主要是符号位,但是在普通的赋值,读写文

  • C语言中sizeof函数踩过的坑总结

    sizeof很简单,但是却很容易令人踩坑. 正文 先来看这样一段代码 int main() { int i=2; printf("%d\n",sizeof(i++)); printf("%d\n",i); return 0; } 非常简单的一段代码 当时我认为答案应该是 4 3 可是结果却是出乎我的意料了 这是为什么呢? 下面来仔细说一下 通过调试观察虽然确实有i++这么一句代码,但是却没有实现.说到这里很多人可能犯了和我一样的错误,认为sizeof是一个函数. 其

  • C语言 sizeof 函数详情

    目录 一.sizeof 函数简介 二.sizeof 函数实战 一.sizeof 函数简介 在 C 语言中,char 字符串也是一种非常重要的数据类型,我们除了使用 sizeof 函数获取字符串长度之外,使用 sizeof 函数同样也可以完成字符串长度的获取: 字符串:一般用一对双引号" "括起的一串字符来表示字符串常量,字符串默认以转义字符'\0'结尾,字符串常量是不可被修改的: sizeof 函数会扫描整个字符串,直到碰到第一个字符串结束符 '\0'为止,然后返回计数器值(长度包含'

  • 浅谈C语言中的sizeof()和strlen()的区别

    目录 sizeof() strlen 补一个注意事项: sizeof()和strlen()经常会被初学者混淆,但其中有有很大区别: sizeof() 1. sizeof()[操作数所占空间的字节数大小]是一种c中的基本运算符.可以以类型.指针.数组和函数等作为参数.返回值类型为unsigned int 运算值在编译的时候就出结果,所以可以用来定义数组维数. char a[5]="123"; int b=sizeof(a);//b=5 int c=strlen(a);//c=3 size

  • C语言数据类型与sizeof关键字

    目录 一.前言 二.数据类型 1.数据类型有哪些 2.为什么要有数据类型 3.如何看待数据类型 三.sizeof – 计算不同类型变量开辟空间的大小 1.内置类型开辟的空间大小 2.自定义类型开辟的空间大小 3.指针类型开辟的空间大小 4.空类型开辟的空间大小 四.对sizeof 的进一步理解 1.sizeof 为什么不是函数 2.sizeof 的其他使用 一.前言 大家好,欢迎来到C语言深度解析专栏—C语言关键字详解第三篇,在本篇中我们将会介绍C语言当中的数据类型,并由此引出C语言当中的另外一

  • C语言详解关键字sizeof与unsigned及signed的用法

    目录 最冤枉的关键字sizeof理解 被误解为函数 sizeof(int)*p 表示什么意思 signed与unsigned 关键字 有符号整数vs无符号整数 整形在内存的存储 原码 反码 补码 存储的本质 十进制二进制快速转化 为什么存储的是补码 大小端 最冤枉的关键字sizeof理解 sizeof:确定一种类型在开辟空间的时候的大小. 被误解为函数 sizeof是关键字而不是函数,可以借助编译器来确定它的身份. #include<stdio.h> int main() { int a =

  • C语言详解如何应用模拟字符串和内存函数

    目录 1.strlen 求字符串长度 使用案例: 1.计数法 2.不创建临时变量计数器-递归 3.指针-指针的方式 2.长度不受限制的字符串函数 1.strcpy 使用案例: 模拟实现: 2.strcat 使用案例: 模拟实现: 3.strcmp-比较字符串首字母的大小 使用案例: 模拟实现: 3.长度受限制的字符串函数  1.strncpy 使用案例: 2.strncat  使用案例: 3.strncmp 使用案例: 4.strstr-找子串  使用案例: 模拟实现: 5.strtok 用法:

  • 详解C++ sizeof(下)

    sizeof作用于基本数据类型,在特定的平台和特定的编译器中,结果是确定的,如果使用sizeof计算构造类型:结构体.联合体和类的大小时,情况稍微复杂一些. 1.sizeof计算结构体 考察如下代码: struct S1 { char c; int i; }; cout<<"sizeof(S1)="<<sizeof(S1)<<endl; sizeof(S1)结果是8,并不是想象中的sizeof(char)+sizeof(int)=5.这是因为结构体或

  • C语言详解数据结构与算法中枚举和模拟及排序

    目录 枚举 连号区间数 递增三元组 二分 双指针 前缀和 模拟 特别数的和 错误票据 排序 快速排序 归并排序 枚举 连号区间数 来源:第四届蓝桥杯省赛C++B组,第四届蓝桥杯省赛JAVAB组 小明这些天一直在思考这样一个奇怪而有趣的问题: 在 1∼N 的某个排列中有多少个连号区间呢? 这里所说的连号区间的定义是: 如果区间 [L,R] 里的所有元素(即此排列的第 L 个到第 R 个元素)递增排序后能得到一个长度为 R−L+1 的“连续”数列,则称这个区间连号区间. 当 N 很小的时候,小明可以

  • C语言详解float类型在内存中的存储方式

    目录 1.例子 2.浮点数存储规则 1.例子 int main() { int n = 9; float *pFloat = (float *)&n; printf("n的值为:%d\n",n); printf("*pFloat的值为:%f\n",*pFloat); *pFloat = 9.0; printf("num的值为:%d\n",n); printf("*pFloat的值为:%f\n",*pFloat); re

  • C语言详解如何实现带头双向循环链表

    目录 创建链表存储结构 创建结点 链表的初始化 双向链表的打印 双向链表尾插 双向链表尾删 双向链表头插 双向链表头删 双向链表查找 双向链表pos前插入结点 双向链表删除pos位置的结点 双向链表的销毁 顺序表和链表的区别 2022042311415360.{C}{C}png" /> 创建链表存储结构 我们需要创建一个结构体来存储一个链表结点的相关信息. typedef int ListDataType;//将ListDataType先定义为int类型,根据需要可以改为不同的类型 //创

  • C语言详解冒泡排序实现

    目录 前言 一.冒泡排序是什么 二.具体步骤 1.代码解释 2.读入数据 总结 前言 在排序中,有各种各样的排序方式,今天我们将要来介绍<冒泡排序>.今天会从冒泡排序的具体意义和他的操作来展开. 一.冒泡排序是什么 从左到右,相邻元素进行比较.每次比较一轮,就会找到序列中最大的一个或最小的一个.这个数就会从序列的最右边冒出来. 以从小到大排序为例,第一轮比较后,所有数中最大的那个数就会浮到最右边:第二轮比较后,所有数中第二大的那个数就会浮到倒数第二个位置……就这样一轮一轮地比较,最后实现从小到

  • C语言详解结构体的内存对齐与大小计算

    目录 结构体的内存对齐 1.计算结构体的大小 2.结构体的对齐规则 3.为什么存在内存对齐? 4.总结 结构体的内存对齐 1.计算结构体的大小 struct S1 { char c1; // 1 byte,默认对齐数为8,所以c1的对齐数是1,第一个成员变量放在与结构体变量偏移量为0的地址处 int i; // 4 byte,默认对齐数为8,所以i的对齐数是4,所以i要放到偏移量为 4的整数倍 的地址处 char c2; // 1 byte,默认对齐数为8,所以c2的对齐数是1,所以c2要放到偏

  • C语言 详解字符串基础

    目录 一.字符串的概念 二.字符数组与字符串 三.字符串字面量的秘密 四.字符串的长度 五.小结 一.字符串的概念 字符串是有序字符的集合 字符串是程序中的基本元素之一 C 语言中没有字符串的概念 C 语言中通过特殊的字符数组模拟字符串 C 语言中的字符串是以 ‘\0’ 结尾的字符数组 二.字符数组与字符串 在C语言中,双引号引用的单个或多个字符是—种特殊的字面量 存储于程序的全局只读存诸区 本质为字符数组,编译器自动在结尾加上 ‘\0' 字符 下面看一段字符数组与字符串的代码: #includ

  • C语言详解如何实现顺序栈

    目录 顺序栈的定义 顺序栈的理解 准备工作 具体实现 今天说的是关于数据结构顺序栈的一些基本操作c语言实现. 顺序栈的定义 首先,我们先来简单了解一下顺序栈,前面线性表我们知道,根据顺序存储或者链式存储分为顺序表和单链表,同样的,根据存储方式的不同,我们把栈分为顺序存储的栈称为顺序栈,链式存储的栈称为链栈.我们要讲的就是顺序栈.实际上,有了前面线性表的一些知识后,关于栈的操作我们还是比较容易理解的. 顺序栈的理解 问题来了?我们怎么去定义呢?通常我们可以用一个数组和记录栈顶元素位置的变量组成,栈

随机推荐