/*
位运算:
1.用于对数据某一位进行操作(置0或者置1)
2.优点:直接操作二进制,效率更高
3.注意:但凡涉及到位运算符,都需要先将数字转成二进制再进行计算。
4.所有位运算的计算都是用补码来进行计算
*/
/*
位运算符:
按位与 :&
按位或 :|
按位异或:^
按位取反:~
按位左移:<<
按位右移:>>
*/
int main(void)
{
#if 0
/*
按位与:&:全1才为1,有0则为0
*/
char ch1 = -67, ch2 = 89;
char ch3 = ch1 & ch2;
/*
ch1 = -67 源码:1100 0011
反码:1011 1100
补码:1011 1101
ch2 = 89 源码:0101 1001
反码:0101 1001
补码:0101 1001
ch1 补码:1011 1101
&
ch2 补码:0101 1001
------------------------------
补码: 0001 1001
反码:0001 1001
ch3: 源码:0001 1001
*/
printf("ch3 = %d\n",ch3);
/*
按位或:| 有1则为1,全0才为0
*/
char ch1 = -67, ch2 = 89;
char ch3 = ch1 | ch2;
/*
ch1 = -67 源码:1100 0011
反码:1011 1100
补码:1011 1101
ch2 = 89 源码:0101 1001
反码:0101 1001
补码:0101 1001
ch1 补码:1011 1101
|
ch2 补码:0101 1001
------------------------------
补码: 1111 1101
反码:1111 1100
ch3: 源码:1000 0011 = -3
*/
printf("ch3 = %d\n", ch3);
/*
按位异或:^:相同为0,不同为1
*/
char ch1 = -67, ch2 = 89;
char ch3 = ch1 ^ ch2;
/*
ch1 = -67 源码:1100 0011
反码:1011 1100
补码:1011 1101
ch2 = 89 源码:0101 1001
反码:0101 1001
补码:0101 1001
ch1 补码:1011 1101
^
ch2 补码:0101 1001
------------------------------
补码: 1110 0100
反码:1110 0011
ch3: 源码:1001 1100 = -28
*/
printf("ch3 = %d\n", ch3);
/*
按位左移:<< 高位溢出n位,低位补n个0
*/
char ch1 = -67;
char ch3 = ch1 << 3;//ch1左移3位
/*
ch1 = -67 源码:1100 0011
反码:1011 1100
补码:1011 1101
ch1 补码:1011 1101
------------------------------
ch1<<3 补码: 1110 1000
反码:1110 0111
源码:1001 1000-->-24
*/
printf("ch3 = %d\n", ch3);
#endif
/*
按位右移:>> 低溢出n位,高位补n个0
*/
char ch1 = -67;
//char ch2 = -34;
char ch3 = ch1 >> 3;//ch1右移3位
/*
ch1 = -67 源码:1100 0011
反码:1011 1100
补码:1011 1101
ch1 补码:1011 1101>> 3
0001 1111 1111 1111 1111 1111 1111 0111
------------------------------
ch1>>3 补码: 1111 0111
反码:1111 0110
源码:1000 1001
*/
printf("ch3 = %d\n", ch3);
return 0;
}
位运算练习
#include <stdio.h>
/*
有一个整型数int num= 0x12345678;
要求将整型数num的每一个字节取出进行相加
最后打印相加的结果(使用位运算实现)
int sum = 0x12 + 0x34 + 0x56 + 0x78
*/
int main(void)
{
int num = 0x12345678;
int temp = 0b11111111;
int n1, n2, n3, n4;
n1 = num & temp;
n2 = (num >> 8) & temp;
n3 = (num >> 16) & temp;
n4 = (num >> 24) & temp;
int sum = n1 + n2 + n3 + n4;
printf("sum = %d\n",sum);
return 0;
}
#include <stdio.h>
/*
字节序:对于多字节的基本整形数据类型,有字节顺序的问题
*/
/*
字节序的分类:
大端序:高字节存放在低地址,低字节存放在高地址(网络序)
小端序:高字节存放在高地址,低字节存放在低地址
*/
/*
面试:
1.什么是字节序:
字节序(Byte Order)是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
在计算机中是以字节为单位,每个地址对应一个字节,一个字节8bit。在C中,除了8bit的char以外,还有16bit的short,32位的int,64位long,当然具体要由编译器决定,可以通过sizeof来获取不同类型在内存中占用的字节数。在计算机系统中,当物理单位的长度大于1个字节时,就要区分字节顺序。
常见的字节顺序有两种:大端(Big-endian)和小端(Little-endian),当然还有其他字节顺序,但不常见,例如Middle Endian。
2.如何判断大小端?
方法一: 使用强制类型转换
#include <iostream>
using namespace std;
int main()
{
int a = 0x1234;
//由于 int 和 char 的长度不同,借助 int 型转换成 char 型,只会留下低地址的部分
char b = (char)(a);
if (b == 0x12)
cout << "big endian" << endl;
else if(b == 0x34)
cout << "little endian" << endl;
}
方法二:使用联合体union
结构体和联合体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而联合体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),联合体占用的内存等于最长的成员占用的内存。联合体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。
#include <iostream>
using namespace std;
// 联合体占用内存的空间为每个成员字节长度的最大值
union endian
{
int a;
char b;
};
int main()
{
endian e;
e.a = 0x1234;
// a 和 b 共用 4 字节的内存空间
if (e.b == 0x12)
cout << "big endian"<<endl;
else if (e.b == 0x34)
cout << "little endian"<<endl;
}
原文链接:https://blog.csdn.net/sjp1992/article/details/120040247
3.如何避免大小端带来的影响?
答:避免传输多字节的数据类型,可以使用字符数组
*/
int main(void)
{
int num = 0x12345678;
char ch = num; //类型转换:取低地址的内容
printf("ch = %#x\n",ch);
char str[4] = { 0x12,0x34,0x56,0x78 };
ch = str[0];
printf("ch = %#x\n",ch);
return 0;
}
三目运算符
#include <stdio.h>
/*
三目运算符:
1.操作数:3
2.优先级:仅高于 赋值运算符和逗号运算符
3.结合性:从右往左
4.语法格式:表达式1?表达式2:表达式3;
5.语法规则:相当于一个简单的if...else 语句
6.运行结果:表达式2或者表达式3运行的结果
*/
/*
表达式1?表达式2:表达式3;
if(表达式1)
{
表达式2;
}
else
{
表达式3;
}
*/
int main(void)
{
int num1 = 10, num2 = 10;
//int ret = num1 > num2 ? num1++ : --num2;
int ret = num2 = num1++ > num2++ ? num1++ : --num2;
printf("num1 = %d,num2 = %d,ret = %d\n",num1,num2,ret);
return 0;
}
三目运算符的练习
#include <stdio.h>
/*
写一个宏函数,实现比较两个表达式的大小,返回较小值(用三目运算符实现)
写一个宏函数,实现比较两个表达式的大小,返回较大值(用三目运算符实现)
*/
#define MIN(A,B) (((A) < (B)) ? (A) : (B))
//#define MAX(A,B) (((A) > (B)) ? (A) : (B))
#define MAX(a,b) (((long)((a)-(b))&0x80000000)?(b):(a))
int main(void)
{
int a = 200, b = 100;
//int ret = MIN(a, b)
//int ret = ((a = b++) < (a > b ? a : b)) ? (a = b++):(a > b ? a : b);
// ret = a = 0
int ret = MIN(a = b++,a > b ? a : b);
printf("ret = %d\n",ret);
return 0;
}
#include <stdio.h>
/*
复合赋值运算符:
+= -= /= *= %= ^= ~=
int a = 10;
a += 10; //a = a + 10;
*/
int main(void)
{
return 0;
}
#include <stdio.h>
/*
逗号表达式:
1.语法规则:从左往右依次计算每个表达式,然后
将最后一个表达式作为整个表达式的结果
2.注意事项:逗号表达式最好加上括号,防止产生歧义
*/
int main(void)
{
int n1 = 10, n2 = 20, n3 = 30;
// 13 22
//int ret = (n1++, ++n2, n2++, ++n1, n1++);
int ret;
//为了防止歧义,逗号表达式最好加上括号
ret= n1++, ++n2, n2++, ++n1, n1++;
printf("n1 = %d,n2 = %d,n3 = %d,ret = %d\n",n1,n2,n3,ret);
return 0;
}
#include <stdio.h>
/*
所谓关系运算符:其实表示的就是表达式和表达式之间的关系
> < >= <=
==:判断两个表达式是否相等
!=:判断两个表达式是否不相等
关系运算符运算的结果:
成立:1
不成立:0
*/
int main(void)
{
int ret = 1 > 3;
printf("ret = %d\n",ret);
int num1 = 18, num2 = 20;
if (num1 > num2)
{
printf("成立!\n");
}
else
{
printf("不成立!\n");
}
//ret = num1 == num2;
ret = num1 != num2;
printf("ret = %d\n",ret);
int b = 5 > 4 > 3;
printf("b = %d\n",b);
return 0;
}