变长参数列表

头文件定义了一些宏,当函数参数未知时去获取函数的参数

变量:typedef va_list

宏:

va_start()

va_arg()

va_end()

va_list类型通过stdarg宏定义来访问一个函数的参数表,参数列表的末尾会用省略号省略

(va_list用来保存va_start,va_end所需信息的一种类型。为了访问变长参数列表中的参数,必须声明va_list类型的一个对象 )

我们通过初始化(va_start)类型为va_list的参数表指针,并通过va_arg来获取下一个参数。

【例子:】

求任意个整数的最大值:

可变长数组

历史上,C语言只支持在编译时就能确定大小的数组。程序员需要变长数组时,不得不用malloc或calloc这样的函数为这些数组分配存储空间,且涉及到多维数组时,不得不显示地编码,用行优先索引将多维数组映射到一维的数组。

ISOC99引入了一种能力,允许数组的维度是表达式,在数组被分配的时候才计算出来。

注意:如果你需要有着变长大小的临时存储,并且其生命周期在变量内部时,可考虑VLA(Variable Length Array,变长数组)。但这有个限制:每个函数的空间不能超过数百字节。因为C99指出边长数组能自动存储,它们像其他自动变量一样受限于同一作用域。即便标准未明确规定,VLA的实现都是把内存数据放到栈中。VLA的最大长度为SIZE_MAX字节。考虑到目标平台的栈大小,我们必须更加谨慎小心,以保证程序不会面临栈溢出、下个内存段的数据损坏的尴尬局面。

case支持范围取值(gcc扩展特性) MinGW编译通过

非局部跳转setjmp和longjmp

在C中,goto语句是不能跨越函数的,而执行这类跳转功能的是setjmp和longjmp宏。这两个宏对于处理发生在深层嵌套函数调用中的出错情况是非常有用的。

此即为:非局部跳转。非局部指的是,这不是由普通C语言goto语句在一个函数内实施的跳转,而是在栈上跳过若干调用帧,返回到当前函数调用路径的某个函数中。

#include

int setjmp(jmp_buf env) ; /*设置调转点*/

void longjmp(jmp_bufenv, int val) ; /*跳转*/

setjmp参数env的类型是一个特殊类型jmp_buf。这一数据类型是某种形式的数组,其中存放 在调用longjmp时能用来恢复栈状态的所有信息。因为需在另一个函数中引用env变量,所以应该将env变量定义为全局变量。

longjmp参数val,它将成为从setjmp处返回的值。(很神奇吧。setjmp根据返回值可知道是哪个longjmp返回来的)

volatile属性

如果你有一个自动变量,而又不想它被编译器优化进寄存器,则可定义其为有volatile属性。这样,就明确地把这个值放在存储器中,而不会被优化进寄存器。

setjmp会保存当前栈状态信息,也会保存此时寄存器中的值。(longjmp会回滚寄存器中的值)

【如果要编写一个使用非局部跳转的可移植程序,则必须使用volatile属性】

· IO缓冲问题

缓冲输出和内存分配

当一个程序产生输出时,能够立即看到它有多重要?这取决于程序。

例如,终端上显示输出并要求人们坐在终端前面回答一个问题,人们能够看到输出以知道该输入什么就显得至关重要了。另一方面,如果输出到一个文件中,并最终被发送到一个行式打印机,只有所有的输出最终能够到达那里是重要的。

立即安排输出的显示通常比将其暂时保存在一大块一起输出要昂贵得多。因此,C实现通常允许程序员控制产生多少输出后在实际地写出它们。

这个控制通常约定为一个称为setbuf()的库函数。如果buf是一个具有适当大小的字符数组,则

setbuf(stdout, buf);

将告诉I/O库写入到stdout中的输出要以buf作为一个输出缓冲,并且等到buf满了或程序员直接调用fflush()再实际写出。缓冲区的合适的大小在中定义为BUFSIZ。

因此,下面的程序解释了通过使用setbuf()来讲标准输入复制到标准输出:

不幸的是,这个程序是错误的,因为一个细微的原因。

要知道毛病出在哪,我们需要知道缓冲区最后一次刷新是在什么时候。答案:主程序完成之后,库将控制交回到操作系统之前所执行的清理的一部分。在这一时刻,缓冲区已经被释放了! (即main函数栈清空之后)

有两种方法可以避免这一问题。

首先,使用静态缓冲区,或者将其显式地声明为静态:

static char buf[BUFSIZ];

或者将整个声明移到主函数之外。

另一种可能的方法是动态地分配缓冲区并且从不释放它:

char *malloc();

setbuf(stdout, malloc(BUFSIZ));

注意在后一种情况中,不必检查malloc()的返回值,因为如果它失败了,会返回一个空指针。而setbuf()可以接受一个空指针作为其第二个参数,这将使得stdout变成非缓冲的。这会运行得很慢,但它是可以运行的。

预编译和宏定义

C/C++中几个罕见却有用的预编译和宏定义

1:# error

语法格式如下:

#error token-sequence

其主要的作用是在编译的时候输出编译错误信息token-sequence,从方便程序员检查程序中出现的错误。例如下面的程序

在编译的时候输出如编译信息

fatal error C1189: #error : No definedConstant Symbol CONST_NAME1

2:#pragma

其语法格式如下:

# pragma token-sequence

此指令的作用是触发所定义的动作。如果token-sequence存在,则触发相应的动作,否则忽略。此指令一般为编译系统所使用。例如在Visual C++.Net 中利用# pragma once 防止同一代码被包含多次。

3:#line

此命令主要是为强制编译器按指定的行号,开始对源程序的代码重新编号,在调试的时候,可以按此规定输出错误代码的准确位置。

形式1

语法格式如下:

# line constant “filename”

其作用是使得其后的源代码从指定的行号constant重新开始编号,并将当前文件的名命名为filename。例如下面的程序如下:

提示如下的编译信息:

Hello.c(15) : error C2065: 'CONST_NAME1' :undeclared identifier

表示当前文件的名称被认为是Hello.c, #line 10 "Hello.c"所在的行被认为是第10行,因此提示第15行出错。

形式2

语法格式如下:

# line constant

其作用在于编译的时候,准确输出出错代码所在的位置(行号),而在源程序中并不出现行号,从而方便程序员准确定位。

4:运算符#和##

在ANSI C中为预编译指令定义了两个运算符——#和##。

# 的作用是实现文本替换(字符串化),例如

#define HI(x)printf("Hi,"#x"");

void main()

{

HI(John);

}

程序的运行结果

Hi,John

在预编译处理的时候, #x的作用是将x替换为所代表的字符序列。(即把x宏变量字符串化)在本程序中x为John,所以构建新串“Hi,John”。

##的作用是串连接。

例如

#define CONNECT(x,y) x##y

void main()

{

int a1,a2,a3;

CONNECT(a,1)=0;

CONNECT(a,2)=12;

a3=4;

printf("a1=%da2=%da3=%d

语言const的生命周期_C语言的角落——这些C语言不常用的特性你知道吗?相关推荐

  1. 语言const的生命周期_第3课-进化后的const分析

    一.C语言中的const (1) const修饰的变量是只读的,本质还是变量: (2) const修饰的局部变量在栈上分配空间: (3) const修饰的全局变量在只读存储区分配空间: (4) con ...

  2. 语言const的生命周期_如何理解一门编程语言2——以复制构造函数为例

    前些天我发布了一篇文章<如何理解一门编程语言>,文中我以C++中的const为例,给大家分享了如何通过修饰词的修饰对象来理解编程语言中晦涩难记的语法. 如果把 const 作为一个形容词来 ...

  3. c语言程序的生命周期(编写、预处理、编译、汇编、链接、执行)

    目录 程序的生命周期 一.引言 二.程序经历的六个阶段 1.阶段一:编辑(Edit) 2.程序编译系统(Programs Compilation System) 阶段二:预处理(Preprocess) ...

  4. c语言变量作用域生命周期,C/C++——C++变量的作用域与生命周期,C语言中变量的作用域和生命周期...

    谭浩强书: 从存储模型可以看到,谭浩强和钱能的模型有一定的对应关系: 静态存储区  ->  全局数据区 动态存储区  ->  栈(stack) 变量的类型: 1. 局部变量和全局变量 局部 ...

  5. mark关于Java语言Static的生命周期

    1.Java客户端开发时用static类保存静态数据是常用做法,其生命周期和程序一样: 2.类源码移植到web开发时,static定义的类型就会出现问题,容易出现多用户共享数据,如静态队列定义,多用户 ...

  6. c语言变量生存期,C语言变量的生命周期

    变量的存储期是指程序运行过程中,变量在内存中的生存期,可以理解为变量的寿命.C语言中变量的存储期有自动存储期和静态存储期两种. 一般情况下,变量的存储期和作用域是紧密相关的.在函数外面定义的全局变量都 ...

  7. c语言if多条件并列_C/C++编程笔记:C语言预编译指令—条件编译,零基础推荐收藏

    一. 内容概述 本文主要介绍c语言中条件编译相关的预编译指令,包括#define.#undef.#ifdef.#ifndef.#if.#elif.#else.#endif.defined. 二.条件编 ...

  8. JAVA 临时变量的生命周期_C++临时变量的生命周期?

    另一个回答已经说明白了,不过有的编译器上可能有坑:It isimplementation-defined whether the lifetime of a parameter ends when t ...

  9. 微信小程序 - 自定义组件中类似页面 onShow 的页面显示就触发的生命周期钩子函数(页面回退时更新数据常用, 例如回退页面更新子组件数据, 回退更新子组件中 data 内容)

    前言 在微信小程序中,用户回退页面触发更新数据的操作,一般都是在 页面 onShow() 中写上执行更新的函数即可. 但如果咱们把数据和方法都写在了自定义子组件中,那么用户回退页面时, 更新数据就成了 ...

最新文章

  1. Plotly绘制时间序列图实战:简单时序图、时间范围限制的时序图
  2. Windows Server 2016第三个技术预览版新技术
  3. 记一则神秘JDK版本引发的hadoop集群慢性崩溃”血案“
  4. 如何获取真实的执行计划
  5. 日常生活小技巧 -- word中插入visio和视频
  6. 简单介绍强引用,软引用,弱引用,虚引用
  7. 【Servlet】JSP学习-概念和运行原理
  8. LeetCode —— 深搜水题记录
  9. 8 天扩容超 100 万核,腾讯会议正在刷新历史
  10. Singular Value Decomposition(SVD)--奇异值分解【转】
  11. c语言 adt实验报告,Android实验报告
  12. windows cmd命令行添加mysql环境变量
  13. 单片机中使用三极管驱动蜂鸣器
  14. 【解题报告】Kattis - adjoin 树形dp
  15. 图片上传之blob对象预览
  16. 2016年淘宝购买华硕FL5900UQ7500惨痛经历教训总结
  17. 科技爱好者周刊(第 106 期):数字游民
  18. 【Vue 快速入门系列】Vue数据实现本地存储、自定义事件绑定、全局事件总线、$nextTick的使用
  19. 1-18 Collections工具类和StreamAPI流式编程
  20. LF 和 CRLF 是什么

热门文章

  1. 对 jiffies 溢出、回绕及 time_after 宏的理解
  2. java设计模式---构建者模式
  3. Linux : SUID SGID
  4. Android 如何退出程序
  5. TCP/IP详解--学习笔记(5)-IP选路,动态选路,和一些细节
  6. Xen的内存布局及其启动
  7. Problem 60 关于解决X11的错误的问题?
  8. html制作顶部选项卡,html: 原生javascript实现选项卡
  9. TCP校验和的设计与实现
  10. html绘制圆形和弧形的代码,通过HTML5 Canvas API绘制弧线和圆形的教程