变长参数列表

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

变量: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

void函数调用时显示不允许使用不完整的_C语言的角落——这些C语言不常用的特性你知道吗?...相关推荐

  1. void函数调用时显示不允许使用不完整的_4位数码管显示模块驱动

    TM1637四位数码管模块是一个带时钟点的4位共阳数码管(0.36英寸)的显示模块,驱动芯片为TM1637,驱动方式为IIC,因此只需2根信号线即可使单片机控制4位8段数码管(数码管8级亮度可调). ...

  2. .net调用c++方法时如何释放c++中分配的内存_C/C++编程笔记:C语言编程知识要点总结!大一C语言知识点(全)...

    一.C语言程序的构成 与C++.Java相比,C语言其实很简单,但却非常重要.因为它是C++.Java的基础.不把C语言基础打扎实,很难成为程序员高手. 1.C语言的结构 先通过一个简单的例子,把C语 ...

  3. (PD)PowerDesigner设计表时显示注释列Comment,Columns中没有Comment的解决办法(关联MySQL)

    1.在所要编辑的表上双击,打开Table Properties窗口,并将上面的选项卡切换到Columns,如下图: 2.点击Customize Columns and Filter按钮,下图红框中的按 ...

  4. c语言void类型函数调用不可作为,对于void类型函数调用时不可作为

    c语言 void函数怎么调用 当n=123114350时, 结果为:c1=3 c2=1 c3=2 int c1, c2, c3; void fun(lon[void的含义] void的字面意思是&qu ...

  5. android 弹出对话框时显示键盘

    今天,简单讲讲如何在弹出自定义的对话框时,弹出软键盘. 之前,我讲了如何制作自定义的对话框,现在,如果在弹出对话框时,自动弹出软键盘,将光标直接聚焦到自定义对话框的输入框内,那该怎么做呢? 在网上搜索 ...

  6. android加载刷新进度条,android – 在Activity加载时显示进度条

    我有一个ListActivity,它基于列表选择启动另一个Activity.第二个Activity需要从互联网上加载一些相当数据的数据,因此在用户点击一个项目和Activity显示之间有一个明显的延迟 ...

  7. 看代码学知识之(2) ListView无数据时显示其他View

    看代码学知识之(2) ListView无数据时显示其他View 今天看的一块布局是这样的: <!--The frame layout is here since we will be showi ...

  8. java 字节码查看_一种查看java字节码时显示方法调用关系图的方法与流程

    本发明涉及一种代码逻辑分析方法,具体涉及一种查看java字节码时显示方法调用关系图的方法. 背景技术: 目前软件反编译领域有不少对可执行文件进行反编译的工具如IDA,也有对Java代码生成的中间码文件 ...

  9. 在c语言程序中,数组名做函数调用的实参时,传递给形参的是,若用数组名作为函数调用时的实参,则实际上传递给的形参的是(C)...

    若用数组名作为函数调用时的实参,则实际上传递给形参的是数组首地址. 数组首地址数组第一个元素的地址.数组名字本身就是一个指针,它是一个指针常量,指向的地址不变. 比如定义了一个数组变量,编译器就会在内 ...

最新文章

  1. $Django 中间件 csrf
  2. 因xhost命令和DISPLAY环境变量操作不当导致无法启动Oracle图形化安装界面
  3. Java I/O模型从BIO到NIO和Reactor模式
  4. OpenCASCADE绘制测试线束:数据交换命令之一般命令
  5. java 异步处理数据格式_spring mvc对异步请求的处理
  6. WebView 的新增安全功能
  7. vue 3.0记录Element UI 表单使用(看了隔壁小孩儿都会用的Element UI 表单组件使用)
  8. 七夕动态表白代码,基于python
  9. 制作中国范围地图的几点注意事项
  10. VUE调用高德地图之热力图
  11. 卸载Windows下驱动并删除sys文件
  12. VeryCD关闭音乐视频下载视频网站的正版化历程
  13. 5.5 Go语言项目实战:多人聊天室
  14. 将标准的EclipseWTP项目转化成具有Gradle功能的EclipseWTP项目
  15. 荐读:FPGA设计经验之图像处理
  16. imprecise external abort
  17. android bluedroid 协议栈里面的各个组件之间的消息处理机制
  18. Centos系统mysql 忘记root用户的密码
  19. MySQL安装与配置my.ini
  20. linux启动jar后运行其他命令,Linux 部署jar 后台持续运行

热门文章

  1. Nested Mappings
  2. partprobe源码分析
  3. portscaner 多线程、多协程并发端口扫描
  4. MySQL数据表命令
  5. 云计算时代的数据库运行
  6. Qt字符编码,创建中文文件
  7. ruby gems列表
  8. BIEE-CSS样式大全
  9. centos删除系统自带的httpd
  10. Android网络编程系列 一 Socket抽象层