C语言深度剖析 -- 深度理解符号

发布时间:2024年01月09日


我们为什么要深入理解C语言中的符号呢?符号有什么好说的呀?符号就像我们写代码中的桥梁,没有符号,我们是不可以从桥的一端通向另一端的!C语言中的符号本身不多,也就二十几个。
在这里插入图片描述

注释符号

写注释使我们代码的一个好的优点,注释我们需要简而精,注释要做到:简单、一动,不存在二义性,简单的代码不需要加上注释;

C语言的注释有两种,一种是 /* */、一种是 //

#include <stdio.h>

int main()
{
	int /*   */ i = 10;//正确
	char* s = "abcdef   //ghigk";//正确
	//Is it a\
	valid comment?     //正确,反斜杠\表示续航符
	in/* */t j = 20;//错误
	return 0;
}

注意1:注释本质是被替换成空格的
例如:

在这里插入图片描述
这种写法就是正确的,我们从而也可以知道# 与 define之间是可以带空格的;

注意2:c风格的注释是无法嵌套的

在这里插入图片描述
这样编译器会报错,/* 总会与离他最近的 */匹配

y=x/*p

我们本意是要拿x除以指向p里面的值,我们测试一下

	int x = 10;
	int y = 0;
	int z = 5;
	int* p = &z;
	y = x / * p;
	printf("%d\n", y);

如果我们要写成y = x /* p;这样编译器是会把 /* 识别成注释的;这种情况我们应写成y = x / * p;或者y = x/(*p);;
/与*之间没有空格,编译器就会把/*认为成是注释的开始

条件编译

我们都知道,有些软件会分为会员和非会员,而非会员的部分功能是无法使用的,那么在设计程序时,我们需要写两部分吗?肯定是不需要的,我们只需要将那些会员功能给隐藏就可以了;这里就会用到条件编译,当达到某些条件时,才会执行这些代码!
例如:

#include <stdio.h>

int main()
{
//条件编译
#if 0 //0就是不执行,非0就是执行
	printf("for test1\n");
	printf("for test2\n");
#endif

	//基于条件编译,我们还可以这样写,但是不推荐这样写
	if (0)
	{
		printf("for test1\n");
		printf("for test2\n");
	}
	return 0;
}

续行符与转义符 \

//1.\作为续行符
	int a = 1;
	int b = 2;
	int c = 3;
	if (a == 1 && \
		b == 2 && \
		c == 3) {
		printf("hello world\n");
	}

	//2.\作为转义符
	printf("h\tello wor\nld!\n");

在这里插入图片描述
这里:\t 相当于 table键;\n表示换行

注意:\作为续行符时,后面不可以加空格,否则会报错,前面可以有空格

回车与换行的区别

回车(\r)是将光标移动到该行的开始,换行(\n)就是将光标移动到下一行; 回车加上换行才是我们理解上的回车(键盘上的enter键)
在这里插入图片描述
我们可以实现一个倒计时:

#include <stdio.h>
#include <Windows.h>

int main()
{
	int i = 10;
	while (i >= 0)
	{
		Sleep(1000);
		printf("%2d\r", i--);// \r表示回车,移动到该行的最开始
	}
	return 0;
}

单引号与双引号

单引号表示字符,而双引号表示字符串

printf("%d\n", sizeof(1));//4
printf("%d\n", sizeof('1'));//4
printf("%d\n", sizeof("1"));//2,要加上字符串结束标志
char c = '1';
printf("%d\n", sizeof(c));//1

C99标准的规定,'a’叫做整形常量字符,被看成int型,所以sizeof(‘1’)是4个字节大小,而char类型是占用一个字节的空间;char c = 'abcd'; printf("%c\n", c);//d所以这样的代码是正确的,但是单引号里面最多有四个字符,因为’ '看成int型,我们在最开始就说过先开辟好空间,再把变量存放进去,所以高位abc就被舍弃了,字符c里面只存储了一个字符d!

特殊情况:

printf("%d\n", sizeof(''));//报错
printf("%d\n", sizeof(""));//1,只有一个字符串结束标志\0

逻辑运算符

  1. &&:逻辑与,有假则假
  2. ||:逻辑或,有真则真

这里面的基础语法就不说了,我么只要知道逻辑运算符具有短路的运算规则;就是有一个条件不满足时,后面的条件就不再看了;

demo:

#include <stdio.h>

int show()
{
	printf("you can see me!\n");
	return 1;
}

int main()
{
	int a = 0;
	scanf("%d", &a);
	a == 10 && show();//当输入的a值不是10时,后面的show函数自动不执行
	return 0;
}

位运算符

&、|、^

按位与(&)、按位或(|)、按位异或(^)都是逐比特位进行位运算的!
我们主要来理解一下按位异或;

按位异或:逐比特位比较,相同为0,相异为1

按位异或满足交换律与结合律;例如:看一个现象

	printf("%d\n", 5 ^ 4 ^ 5);//4
	printf("%d\n", 5 ^ 5 ^ 4);//4
	printf("%d\n", 5 ^ (5 ^ 4));//4

根据按位异或满足交换律与结合律,我们可以通过这个规律来实现两个数交换(不使用中间变量)

#include <stdio.h>

int main()
{
	//方法1:有整形溢出的风险
	int a = 10;
	int b = 20;
	printf("before: a = %d, b = %d\n", a, b);
	a = a + b;
	b = a - b;
	a = a - b;
	printf("after: a = %d, b = %d\n", a, b);

	//方法2:按位异或
	a = 10, b = 20;
	printf("before: a = %d, b = %d\n", a, b);
	a ^= b;
	b ^= a;
	a ^= b;
	printf("after: a = %d, b = %d\n", a, b);
	return 0;
}

在这里插入图片描述
位操作,指定位修改比特位,我们用宏来定义;

#include <stdio.h>

#define SETBIT(x, n) ((x) |= (1 << (n - 1))) //指定比特位为1,用按位或
#define CLRBIT(x, n) ((x) &= (~(1 << (n - 1)))) //指定比特位为0,用按位与(要加上取反符号)

//输出数字的二进制
void ShowBit(int x)
{
	int num = sizeof(x) * 8 - 1;
	while (num >= 0)
	{
		if (x & (1 << num)) printf("1 ");
		else printf("0 ");
		num--;
	}
	puts("");
}

int main()
{
	int x = 0;
	//1.设置指定比特位为1
	SETBIT(x, 5);
	ShowBit(x);
	//2.设置指定比特位为0
	int y = 0xFFFF;
	CLRBIT(y, 5);
	ShowBit(y);
	return 0;
}

整型提升问题

先看现象:

	char c = 0;
	printf("%d\n", sizeof(c));//1
	printf("%d\n", sizeof(~c));//4
	printf("%d\n", sizeof(c << 1));//4
	printf("%d\n", sizeof(c >> 1));//4

无论什么运算符,都是需要计算机运算的,而计算机只有CPU具有运算能力;但数据都是在内存当中,所以计算之前都必须要从内存中拿取数据放到CPU中(CPU中的寄存器中);一般寄存器的位数都是32位,而一个char类型只占一个字符,需要整型提升!!!
但是,有一个特例,在vs中:printf("%d\n", sizeof(!c));//1只占一个字节,但在Linux中却占用四个字节,编译器有自己的理解;

左移 << 右移 >>

  1. 无符号数:最低位舍弃,最高位补0(逻辑左移右移)
  2. 有符号数:最低位舍弃,最高位补符号位(算数左移右移)

注意:0x01 << 2 + 3是多少?

	printf("%d\n", 0x01 << 2 + 3);//32
	printf("%d\n", 0x01 << (2 + 3));//32
	printf("%d\n", (0x01 << 2) + 3);//7

+的优先级比<<高

花括号(了解,不太推荐)

在这里插入图片描述

++、-- 操作符

以++为例:基础语法我们都了解,a++是先使用后++,++a是先++后使用;
如果是b = ++a;是先++在使用(赋值给b),但是如果是直接++a;呢,那怎么先使用呢?其实,不管会不会有值来接受这个值,我们都是将a放到寄存器中来+1操作,我们来看一下汇编代码:

在这里插入图片描述
总结:a++完整的含义是先使用,在自增;如果没有变量接收,那么直接自增,就是读取进寄存器,就没有然后了

来看一个例子:

	int i = 1;
	int j = (++i) + (++i) + (++i);
	printf("%d\n", j);

上面的答案应该是多少呢?C语言与gcc的答案还不太一样,++i是先自增在使用,gcc中先计算前面两个++i,也就是i先自增为2,然后第二个i再自增为3,i这时候在使用都是3,3 + 3 = 6,最后一个i在先自增,为4,在与前两个相加,也就是 3 + 3 + 4 = 10;C语言中,是三个++i同时先自增,最后i变成4,然后 4 + 4 + 4 = 12;

文章来源:https://blog.csdn.net/qq_59702185/article/details/129230075
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。