C语言——小细节和小知识10

一、全局变量和局部变量

1、引例

当全局变量和局部变量名字相同的情况下,局部变量优先。

#include <stdio.h>

int num = 10;

int main()
{
	int num = 0;
	printf("%d\n", num);
	return 0;
}

运行结果

2、介绍

在C语言中,当局部变量和全局变量的名字相同时,程序会优先使用局部变量,这是由语言的作用域规则决定的。作用域是指程序中可以访问变量的区域。以下是两种变量作用域的简要说明:

局部变量

  • 局部变量是在函数或代码块内部定义的变量。
  • 它们只在定义它们的函数或代码块内部可见。
  • 当程序的执行离开该函数或代码块时,局部变量的生命周期结束,并且它们所占用的内存可能被释放或用于其他目的。

全局变量

  • 全局变量是在所有函数和代码块之外定义的变量。
  • 它们在程序的整个运行期间都是可见的,并且它们的值在函数调用之间是持久的。
  • 全局变量的生命周期从它们被定义的时刻开始,直到程序结束。

为什么局部变量优先

  • 这个规则允许函数对外部变量进行"屏蔽",使用自己的局部变量,而不受全局变量的影响。
  • 这是封装和模块化的一个方面,可以防止函数之间因全局变量造成的不必要的数据依赖和影响。
  • 这样,函数可以独立于程序的其他部分工作,使得代码更易于理解和维护。

建议不要全局变量和局部变量名字设为相同。

二、const修饰变量

1、引例

const修饰的常变量既有常属性又有变属性。

	const int num = 0;
	num = 10;

这个写法是错误的,编译器会报错,这是因为const修饰的变量有“常属性”,它们不能被更改。

我们知道C99之前的标准都不允许变长数组,所以数组初始化时[]内只能用常量,例如:

	int arr[10] = { 0 };

但是,如果在C99之前的标准中使用下面的代码,则会报错:

	const int num = 0;
	int arr[num] = { 0 };

这代表num还具有“变属性”。

2、介绍

在C语言中,const 关键字用于声明一个变量为常量。这意味着一旦被初始化后,这个变量的值就不应当被修改。从表面上看,const 修饰的变量具有“常属性”,即它们的值在定义后不可改变。

然而,const 修饰的变量在某些情况下确实展示出一定的“变属性”:

  1. 指针与const

    • const修饰指针时,可以声明指向常量的指针(const*之前)或常量指针(const*之后)。
    • 指向常量的指针意味着不能通过该指针修改其指向的值,但指针自己的值(即存储的地址)可以修改,指向不同的变量。
    • 常量指针则意味着指针存储的地址不可改变,但指向地址的值可以改变。
    • 这个在我之前的文章《C语言——实用调试技巧》中提到过。
  2. 通过指针修改const

    • 尽管const变量本身不应该被修改,但如果将const变量的地址赋给一个非const指针,通过指针间接改变其值是可能的。这样做时,需要强制类型转换来绕过编译器的类型检查,这种行为是未定义的(undefined behavior)并且强烈不推荐。
  3. 存储在可写内存区域

    • const变量通常存储在程序的只读数据段,但如果const变量是通过malloc等动态内存分配函数创建的,它实际上存储在堆区,是可以修改的。

举例来说,如果你声明了一个const整型变量:

const int a = 10;

这个变量a应该在整个程序中保持值不变。尝试修改a,比如a = 20;将会导致编译器错误。

然而,如果你使用指针绕过这个限制,像下面这样:

const int a = 10;
int* p = (int*)&a;
*p = 20;

这个代码片段试图修改一个const变量的值,这是未定义行为。在某些平台和编译器上,它可能导致程序崩溃或其他不可预测的行为,因为a可能存储在只读内存段。即使它“工作了”,这也是一个不好的编程实践,应该避免。

实际上这里虽然表面上a的值被更改了,实际上a的值可能没有变化。

因为:

  1. 编译器优化:因为 a 被声明为 const,编译器可能已经对代码进行了优化,将 a 的值当成一个常量直接嵌入到了代码中,因此打印的时候直接使用了原始的常量值10,而不是去内存中读取 a 的实际值。

  2. 缓存机制:在某些架构中,CPU可能将 const 变量缓存到寄存器中,因此改变内存中的值不会影响到寄存器中的值。

  3. 未定义行为:由于修改 const 变量的值是未定义行为,所以实际上任何结果都是可能的,包括没有改变、改变了值、程序崩溃、或者其他奇怪的副作用。

总体来说,正确使用const可增加程序的可读性和健壮性,它是一个告诉编译器和其他开发者某个值不应被改变的好方法。任何尝试绕过const的方法都是不安全的,并且应该被视为错误的编程实践。

三、硬件和软件

1、大致分层

上层应用软件
下层(底层)操作系统
驱动层
硬件

2、详细分层

更详细的层次结构:

  1. 硬件(Hardware):这是计算机系统的最底层,包括处理器、内存、硬盘、显卡、网络适配器等物理设备。

  2. 固件(Firmware)/BIOS/UEFI:这是软硬件之间的一个中间层,通常嵌入在硬件中,为硬件提供最基本的控制和系统启动的功能。

  3. 驱动层(Drivers):驱动软件使操作系统能够与硬件设备通信。它们通常是操作系统的一部分,但有时也由硬件制造商提供。

  4. 操作系统(Operating System, OS):操作系统是软件与硬件之间的接口层,提供文件管理、内存管理、进程管理等基本服务,并允许用户与系统交互。

  5. 中间件(Middleware):中间件是位于操作系统和应用软件之间的软件,为应用程序提供通信和数据管理的服务,这样的例子包括数据库系统、Web服务器和某些API。

  6. 应用软件(Application Software):这是用户直接使用的软件层,包括办公软件、图像处理软件、游戏、数据库应用程序等。

这是一个模块化的视图,每一层都建立在前一层的基础之上,为上层提供服务。在实际应用中,某些层次可能会有不同的划分方式,特别是在不同的操作系统架构和计算机架构中。

  • 13
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值