C语言的一些疑惑

1.名字与内存位置之间的关联并不是硬件所提供的,它是由编译器为我们实现的。所有这些变量给了我们一种更方便的方法记住地址----硬件仍然通过地址访问内存位置。----------《c和指针》中的一句话。   对于编译器,它会搜集我们的变量名,比如我们定义了一个全局的int a;那么编译器都为我们做了什么呢? 它会为程序预留4个字节的空间(假设在32位平台),并把我们的变量名“a”保存进符号表,并用这个符号表的索引对应实际的空间。变量名不是内存地址。

2.条件编译

#define JUDGE 1

#if JUDGE
    #define parameter 123
#else
    #define parameter 321
#endif

条件编译:parameter在不同的情况下需要定义不同的值,当JUDGE为1时,定义parameter为123;当JUDGE为0时,定义parameter为321

3.关键字volatile

volatile本意为“易变的”。在嵌入式环境中用volatile关键字声明的变量,在每次对其值进行引用的时候都会从原始地址取值,而不会将值保存在栈或其他位置。由于该值“易变”的特性所以,针对其的任何赋值或者获取值操作都会被执行(而不会被优化)。由于这个特性,所以该关键字在嵌入式编译环境中经常用来消除compiler的优化。CPU跑指令去拿数据的时候,正常来说都是通过地址总线去寻址,然后直接从数据总线上拿到对应的数据,拿完之后会放在CPU内部用来存放数据的一些小型存储区域----即寄存器。如果有个变量一直在改,编译器优化后,改完了就放在CPU的寄存器,后面再用到,还是直接从寄存器里面拿,不直接再次访问内存的对应地方了,这样效率就高了。volatile就是告诉编译器每次要用这个变量的时候,不要优化上面的步骤,每次我都从内存对应地方去拿,为什么呢?因为有可能那部分内存是其他地方可能也会改的,如果你还是每次直接从寄存器里面拿,就拿不到最新的数据了。(转自知乎)

4.C库函数重定向:用户能定义自己的C语言库函数,连接器在连接时自动使用这些新的功能函数。这个过程叫做重定向C语言库函数,举例来说,用户有一个I/O设备(如UART)。本来库函数fputc()是把字符输出到调试器控制窗口中去的,但用户把输出设备改成了UART端口,这样一来,所有基于fputc()函数的printf()系列函数输出都被重定向到UART端口上去了。

5.断言“assert_param”实际是一个宏,在库函数中它用于检查输入参数是否符合要求,若不符合要求则执行某个函数输出警告,

assert.h头文件支持的断言库是一个用于辅助调试程序的小型库。它由assert()宏组成,接受一个整型表达式作为参数。如果表达式求值为假(非零),assert()宏就在标准错误流(stderr)中写入一条错误信息,并调用abort()函数终止程序(abort()函数的原型在stdlib.h头文件中)。assert()宏是为了标识出程序中某些条件为真的关键位置,如果其中的一个具体条件为假,就用assert()语句终止程序。通常,assert()的参数是一个条件表达式或逻辑表达式。如果assert()中止了程序,它首先会显示失败的测试、包含测试的文件名和行号。

#ifdef  USE_FULL_ASSERT

/**
  * @brief  The assert_param macro is used for function's parameters check.
  * @param  expr: If expr is false, it calls assert_failed function which reports 
  *         the name of the source file and the source line number of the call 
  *         that failed. If expr is true, it returns no value.
  * @retval None
  */
  #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
  void assert_failed(uint8_t* file, uint32_t line);
#else
  #define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
这段代码的意思是,假如我们不定义“ USE_FULL_ASSERT ”宏,那么“ assert_param ”就是一个空的宏(#else #endif 之间的语句生效 ) ,没有任何操作。从而所有库函数中的assert_param 实际上都无意义,我们就当看不见好了。假如我们定义了“USE_FULL_ASSERT ”宏,那么“ assert_param ”就是一个有操作的语句(#if #else 之间的语句生效 ) ,该宏对参数 expr 使用 C 语言中的问号表达式进行判断,若 expr 值为真,则无操作 (void 0) ,若表达式的值为假,则调用“ assert_failed ”函数,且该函数的输入参数为“__FILE__ ”及“ __LINE__ ”,这两个参数分别代表 “ assert_param ”宏被调用时所在的“文件名”及“行号”。但库文件只对“assert_failed ”写了函数声明,没有写函数定义,实际用时需要用户来定义。
6. 指针常量:说到底是一个常量,只不过这个常量是指针,这个指针的值只能在定义时初始化,其他地方不能修改。指针常量强调的是指针的不可改变性。
    常量指针:一个指向常量的指针,这个指针指向一个只读的对象,不能通过常量指针来改变这个对象的值 。常量指针强调的是指针对其所指对象的不可改变性。
    注 意 :无论是指针常量还是常量指针,其最大的用途就是作为函数的形式参数,保证实参在被调用函数中的不可改变特性 。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值