一.原码、补码、反码
1.二进制表示方式有三种:原码、补码、反码
在32位计算机中整形占4个字节(即32位bite位),最高位符号位为0.代表为正数;负数的最高位为符号位为1。
正数的原码、补码、反码都相同,而负数的原码、补码、反码需要经过计算。
原码到反码再到补码:
反码计算方式:原码的符号位不变,其他位按位取反。
补码计算方式:在反码基础上,符号位不变,反码加1。
而补码到原码:
可用补码减1到反码,再将反码符号位不变,其他位按位取反。
也可将补码符号位不变,先将其他位按位取反,再加1。
负数原码、补码、反码计算方式如下图。
例子
若 unsigned int a=-10;将负数10转换为无符号整形,那么计算机不会将负数10的补码的最高位1当成符号位,而会将其当成有效位。
二.操作符
1.移位操作符
A.左移操作符: <<
移位规则:左边抛弃,右边补0,最高位自动变符号位。
指令表达方式:int n=-10;
n<<1;//表示负数10向左移动一位
而在计算机内存中,存的是数字的补码:在程序中,printf打印的是数字的原码。
B.右移操作符:>>
移位规则:
右移运算分两种:
a.逻辑移位
左边用0填充,右边丢弃。
b.算数移位
左边用原该值的符号位填充,右边丢弃。
注:移位不能移位负数,如n>>-2;
2.位操作符(补码状态进行计算)
&:按位与
两个数的二进制补码对应位相同为1,相异为0;
|:按位或
两个数的二进制补码对应位相有1为1,同时为0才为0;
^:按位异或
两个数的二进制补码对应位相同为0,相异为1;
例.一道变态面试题:
//不允许创建临时变量,交换两个整数的内容
#include<stdio.h>
int main()
{
int a = 2;
int b = 3;
//法一
//a = a + b;//5
//b = a - b;//2
//a = a - b;
//法2
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a=%d\n", a);
printf("b=%d\n", b);
return 0;
}
3.单目操作符
sizeof:
计算操作数的长度,单位字节。
字符串常量赋值给指针变量,赋值过去的是字符串常量首元素的地址。
如char*p="abcdef"
p为指针变量,存的是a的地址;
*p表示解引用,通过找到地址进而找到元素a,而*p也可表示a(即*p=a)。
sizeof后若跟变量名可省略括号,但后面若跟类型则不可省略。
如:
int a=10;
printf("%d\n",sizeof(a));
printf("%d\n",sizeof a);
printf("%d\n",sizeof(int));
//以上打印结果均为4;
sizeof内部的表达式是不计算的
如:
#include <stdio.h>
int main()
{
int a = 10;
short s = 5;
printf("%d\n", sizeof(s = a + 3));
printf("%d\n", s);
}//打印结果为分别为2;3
原因分析:在sizeof后面括号s=a+3不进行计算;
a为int类型,占4个字节,而s为short类型,占2个字节,当一个int类型强行塞进short类型时会发生截断,所以最后还是s说了算。
补充:int和char类型的指针所占大小均为4个字节或者8个字节,具体看编写环境是32位还是64位。
sizeof返回的是无符号整形;
指针补充:若arr为数组名,那么arr代表首元素的地址,所以*arr [ i ]也可写为*[arr +i]。
4.条件操作符
exp1?exp2:exp3;
如:max=(a>b)?a:b;//若a>b为真,则max值为a;若为假,max值为b。
5.逗号表达式
exp1,exp2:exp3......expn;
用逗号隔开的多个表达式,从左到右依次执行,结果取一个表达式的结果。
6.访问结构的成员
·
结构体 ·成员名
->
结构体指针->成员名
如
#include <stdio.h>
struct stu
{
/*int a = 10;
short s = 5;
printf("%d\n", sizeof(s = a + 3));
printf("%d\n", s);*/
char name[10];
int age;
char sex[5];
double score;
}
void set_age1(struct stu stu)//传值
{
stu.age = 18;//访问结构体中age的值
}
void set_age1(struct stu* psstu)//传地址
{
pstu->age = 18;//访问结构体中age的值
}
int main()
{
struct stu stu;
struct stu pstu;
stu.age = 20;
set_age1(stu);
pstu->age = 18;
set_age2(pstu);
return 0;
}
7.隐式类型转换(偷偷转换类型)
整形提升:表达式中的字符和短整型操作数在使用之前被转换为普通整形。
整形提升针对的是小于整形的字节的类型,在整形提升过程中操作的是补码。
负数和正数的整形提升高位补充符号位。
实例
char c1=-1;
11111111(-1的补码)
11111111111111111111111111111111(-1整形提升后的补码)
变量c1的二进制补码中只有8个比特位,所以在整形提升时高位补充符号位1
实例
char a,b,c;
a=b+c;
具体过程:
b和c的值会先被提升为普通整形(4个字节),然后再执行加法运算,加法完成后再赋值给a(a为char类型),结果会被截断,最后再储存到a里面。若需要将a以整形类型打印,需要在打印前将a整形提升再进行打印。
8.自增自减
自增:++
自减:--
实例
int a=1;
int c=2;
c=a++;
printf("%d\n",a);//结果为3
printf("%d\n",c);//先将a赋值给c,c再自增,结果为2
c=++a;
printf("%d\n",a);//结果为3
printf("%d\n",c);//先将a自增,再将a自增后的值赋值给c,结果为3