文件指针偏移, rewind函数,ftell函数 , fseek函数
位操作
位操作与逻辑操作
位操作不同于逻辑操作,逻辑操作是一种整体的操作,而位操作是针对内部数据位补 码的操作。逻辑操作的世界里,只有真与假(零和非零),而位操作的世界里按位论真假 (1 和 0)。运算符也不同,如下。
数据的二进制表示
8 位二进制数据的补码
二进制打印
我们在这里打印特殊值-1 的二进制形式,-1的16进制是ffffffff也进行二进制打印查看是否相同。
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = -1;
int b = 0xffffffff;
dis32bin(a);
dis32bin(b);
return 0;
}
执行结果为:
我们上面所做的二进制打印的目的就是为了我们在位操作之后能够看见操作之后的变化,接下来我们进行位操作说明:
位与(&)
按位与 :&
格式 :x&y
规则 :对应位均为 1 时才为 1,否则为 0
例如 :3&11=3
0011
& 1011
───
0011=3
用途:
在某些位保持不变的情况下,将其余位置 0。
我们进行代码演示:
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 3;
int b = 11;
dis32bin(a);
dis32bin(b);
dis32bin(a&b);
int c = a & b;
c = printf("%d\n",c);
return 0;
}
执行结果为:
我们把a赋值为0x55
b赋值为0xff
打印结果为:
我们可以看到按位&之后,保持不变。
我们把a赋值为0x05
b赋值为0xff
打印结果为:
我们可以看到按位&之后,还是保持不变。
我们把a赋值为0x55
b赋值为0
执行结果为:
我们可以看到按位&之后,结果为全0。
我们把a赋值为0x55
b赋值为0x0f
执行结果为:
我们可以看到和0按位与的部分将会全部清零
和1按位与的部分保持不变。
按位或(|)
按位或 : |
格式 :x|y
规则 :对应位均为 0 时才为 0 ,否则为 1
例如:3|9=11
0011
| 1001
───
1011=11
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 3;
int b = 9;
dis32bin(a);
dis32bin(b);
dis32bin(a|b);
return 0;
}
执行结果为:
我们把a赋值为0x55
b赋值为0
执行结果为:
我们把a赋值为0x55
b赋值为0xff
执行结果为:
我们可以看到和1|之后结果全为1。
我们把a赋值为0x55
b赋值为0x0f
执行结果为:
我们得出结论和1按位或置为1 按0按位置或保持不变。
位取反(~)
按位求反: ~
格式 :~ y
规则 :各位翻转,即原来为 1 的位变成 0,原来为 0 的置 1
例如 :~3=12
~0011
───
1100=12
我们给出代码说明:
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 0x55;
int b = 0x0f;
dis32bin(a);
dis32bin(~a);
return 0;
}
执行结果为:
按位取反。
用途:
间接地构造某个数,省却计算的麻烦,以增强程序的可读性。
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 0x55;
int b = 0x0f;
dis32bin(0);
dis32bin(~0);
return 0;
}
执行结果为:
位异或(^)
按位异或:^
格式 :x^y
规则 :对应相同时 0 ,不同时则为 1。
例如 :3^9=10
0011
^ 1001
────
1010=10
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 3;
int b = 9;
dis32bin(a);
dis32bin(b);
dis32bin(a^b);
return 0;
}
执行结果为:
我们把a赋值为0x55
b赋值为0xff
执行结果为:
我们把a赋值为0x55
b赋值为0
执行结果为:
我们把a赋值为0x55
b赋值为0x0f
执行结果为:
我们可以看到和1取异或结果取反,和0取异或,结果不变。在某些位保持不变的情况下某些为取反。
用途:
相同者归零,相异者或。在某些位保持不变的情况下,将其余位取反。
自身异或,清零
左移(<<)
按位左移:<<
格式 :x<<位数
规则 :使操作数的各位左移,低位补 0,高位溢出。
备注 :位数为非负整数,且默认对 32 求余
例如 : 5<<2 0101 --> 10100
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 5;
dis32bin(a);
dis32bin(a << 2);
return 0;
}
执行结果为:
我们上面体现了低位补0
我们现在来演示一下高位溢出;
我们进行左移31位然后+1
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 5;
dis32bin(a);
dis32bin((a << 31)+1);
return 0;
}
执行结果为:
我们可以看到现在的结果最高位和最低为都是1 现在我们进行进行一次左移操作来体现低位补 0,
高位溢出
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 5;
dis32bin(a);
dis32bin((a << 31));
dis32bin(((a << 31)+1)<<1);
return 0;
}
执行结果为:
如果移位大于32位会出现什么情况:
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 0x01;
dis32bin(a);
dis32bin(a << 31);
dis32bin(a << 32);
dis32bin(a << 33);
dis32bin(a << 34);
return 0;
}
执行结果为:
我们在前面说过左移操作低位补0高位溢出,溢出的部分应该丢掉,但是这里的移动超过了32位,但是结果里面有1。并且在移动都超过32位再增加的时候出现的1在正常左移。
那是不是出现循环的情况呢?
我们通过以下代码进行验证:
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 0xff000000;
dis32bin(a);
dis32bin(a << 1);
dis32bin(a << 2);
dis32bin(a << 3);
return 0;
}
执行结果为:
我们可以看到高位溢出,低位补0没有问题。我们可以看出来,不是循环移位。
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 0xff000000;
dis32bin(a);
dis32bin(a << 32);
dis32bin(a << 33);
dis32bin(a << 34);
return 0;
}
执行结果为:
我们再对于代码进行修改:
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 0xff000000;
dis32bin(a);
dis32bin(a << 0);
dis32bin(a << 1);
dis32bin(a << 2);
printf("\n------------------\n");
dis32bin(a << 32);
dis32bin(a << 33);
dis32bin(a << 34);
return 0;
}
执行结果为:
我们可以发现结果是一样的,我们这里进行说明,当移位超过32位时,移动的位置对32进行取余运算然后进行移位操作。
左移在不溢出的情况下,每左移一位数据大小乘2
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int b = 2;
printf("%d\n", b << 1);
printf("%d\n", b << 2);
printf("%d\n", b << 3);
return 0;
}
执行结果为:
右移>>
按位右移:>>
格式 :x>>位数
规则 :使操作数的各位右移,移出的低位舍弃;
高位 :对无符号数和有符号中的正数补 0;有符号数中的负数,取决于所使用的 系 统: 补 0 的称为“逻辑右移”,补 1 的称为“算术右移”。
说明 :x、y 和“位数”等操作数,都只能是整型(允许字符型数据)。
备注 :位数为非负整数,且默认对 32 求余
高位:无符号的数,有符号的正数。补0
我们进行代码演示:
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 0x1;
dis32bin(a);
dis32bin(a>>1);
printf("\n------------------\n");
a = 0x55;
dis32bin(a);
dis32bin(a >> 4);
printf("\n------------------\n");
unsigned int b = 0x5;
dis32bin(b);
dis32bin(b >> 1);
printf("\n------------------\n");
b = 0x22;
dis32bin(b);
dis32bin(b >> 1);
return 0;
}
执行结果为:
有符号中的负数:补 0 的称为“逻辑右移”,补 1 的称为“算术右移”。
我们给出代码测试:
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int a = 0x800000ff;
dis32bin(a);
dis32bin(a >> 1);
dis32bin(a >> 2);
dis32bin(a >> 3);
return 0;
}
执行结果为:
我们可以看到高位在不断的补1,低位在不断的丢掉1 ,但是不能理解为右边的1补到左边去了。
右移在不溢出的情况下,每右移一位数据大小除2
#include <stdio.h>
void dis32bin(int data)
{
int i = 32;
while (i--)
{
if (data & (1 << i))
printf("1");
else
{
printf("0");
}
if (i % 4 == 0)
{
if (i % 8 == 0)
printf(" ");
else
printf("-");
}
}
putchar(10);
}
int main()
{
int b = 64;
printf("%d\n", b >> 1);
printf("%d\n", b >> 2);
printf("%d\n", b >> 3);
return 0;
}
执行结果为:
优先级
简记结论 :
() > 成员运算 > (!) > 算术> 关系 > 逻辑 > 赋值 > ,
() > 成员运算 > (^/!) >算术> 关系 > (>> <<)位逻辑(&|^) > 逻辑 > 赋值 >
总结
和1按位与不变,和0按位与清零,在某些位保持不变的情况下,某些位清零。
和1按位或置为1,和0按位或保持不变,在某些位保持不变的情况下,某些位置为1。
和1按位异或取反,和0按位异或保持不变,在某些位保持不变的情况下,某些位取反。
左移:高位溢出 低位补零
移位大于32位,移动的位数对于32进行取余然后进行移位操作。
右移:地位舍弃
高位:无符号的数,有符号的正数。补0
有符号中的负数:补 0 的称为“逻辑右移”,补 1 的称为“算术右移”
移位大于32位,移动的位数对于32进行取余然后进行移位操作。
左移在不溢出的情况下,每左移一移位乘2
右移在不溢出的情况下,每右移一移位乘2
这里给出64也是为了移动的时候不溢出,溢出的时候就不能保证这样的规律了。