C语言拾遗
关键字 (Keyword)
asm
asm
asm
-std=c99
__asm__
或-std=gnu99
其中
, "=r"
为操作数的约束 (Constraint) , "="
表示允许覆盖该操作数 , "r"
表示允许使用寄存器 。
1 | int c; |
在_asm
__asm
1 | int a = 5, b; |
case
可以用...
case
1 | case 'A' ... 'Z': |
enum
将整数强制转换为枚举量是允许的
1 | enum Weekday { SUN, MON, TUE, WED, THU, FRI, SAT } day; |
goto
gcc__label__
定义局部标签
You can get the address of a label defined in the current function (or a containing function) with the unary operator&&
. The value is a constant and has type void*
.
1 | const void* arr[] = { &&label1, &&label2, &&label3 }; |
typedef
在语法分析时typedef
1 | const int typedef CINT; // Correct! |
typeof
1 |
字符串 (String)
字面值常量 (Literal)
字面值常量可直接进行拼接操作\0
1 | const char* s1 = "Hello " "World!\n"; |
可对字面值常量寻址
1 | char c = "0123456789"[n % 10]; |
格式 (Formatting)
%p
1 | printf("%p\n", pointer); |
%n
%n
现在多数编译器已不支持
1 | int n; |
结构体 (Structure)
gcc
1 | struct empty { }; |
数组 (Array)
若数组名用于sizeof
sizeof
任何一个数组下标运算都等同于一个对应的指针运算a
和整型i
a+i
i+a
a[i]
i[a]
对于二维数组char (*p)[LEN];
char* p;
零长数组 (Zero-Length Array)
GNU C
1 | struct line { |
变长数组 (VLA; Variable Length Array)
C99
1 | int get(size_t n, int a[n][n], size_t i, size_t j) { |
可以书写上例中get()
1 | int get(int, int[*][*], int, int); |
函数 (Function)
C
K&R 风格函数定义 (K&R Style Function Definition)
现在多数编译器已不支持这种旧式风格函数定义
1 | int isvowel(c) char c; { |
可变参数函数 (Variadic Function)
见stdarg.h
表达式 (Expression)
三元表达式?:
x ?: y
x
非零则为x
y
x ? x : y
GNU Cvoid
)
1 | printf("%d\n", ({1; 2; 3;}) == 3); // 1 |
达夫设备 (Duff's Device)
过去为提高效率而设计
1 | void send(char* to, char* from, int count) { |
平方根倒数速算法 (Fast Inverse Square Root)
出自游戏
1 | float Q_rsqrt(float number) { |
三字符组 (Trigraph)
三字符组又译作三合字母-trigraphs
1 | int main(void) |
转义字符\?
预处理器 (Preprocessor)
__FILE__
和__LINE__
是内建于预处理器中的宏
预处理器中有如下的特殊的操作符
#
将宏参数的代码字符串转化为字符串常量: ; ##
连接两个代码字符串: ; #@
将宏参数的代码转换为字符常量: 。
可变参数宏 (Variadic Macro)
C99/C++特性...
__VA_ARGS__
为替换列表##__VA_ARGS__
表示当可变参数为
借此可以书写宏的
1 |
结构体打包指令 (Structure-Packing Pragma)
结构体打包指令可更改结构体成员的最大对齐
1 |
参数是较小的
#pragma pack(push[,n])
#pragma pack(pop)
#pragma pack(n)
最终
内置函数 (Builtin)
内置函数以__builtin
unsigned int
long
long long
__builtin_clzll
)
__builtin_ffs(n)
(Find First Signed)n
的最后一位n
1 | printf("%d\n", __builtin_ffs(4) == 3); // 1 |
__builtin_clz(n)
(Count of Leading Zeros)
1 | inline int highbit(int x) { return 31 - __builtin_clz(x); } |
__builtin_ctz(n)
(Count of Trailing Zeros)__builtin_clz
__builtin_popcount(n)
__builtin_parity(n)
标准库 (Standard Library)
time.h
time.h
纪元time()
time_t
time()
1 | time_t time(time_t* arg); |
time()
arg
time_t
arg
可以通过如下代码测量实际用时
其中
: clock()
返回程序执行起处理器时钟所用的时间 ; CLOCKS_PER_SEC
是每秒走过的计时数 , CLK_TCK
与之等效 但被视为已过时 , 。
1 | clock_t start, stop; |
标准日期时间字符串的格式为Www Mmm dd hh:mm:ss yyyy\n
asctime()
将日历时间: struct tm
; ctime()
将纪元起的时间: time_t
。
strftime()
1 | if (strftime(buff, sizeof buff, "...", &my_tm)) puts(buff); |
纪元起的时间与日历时间的相互转换如下
gmtime()
将纪元起的时间: time_t
struct tm
; localtime()
将纪元起的时间: time_t
struct tm
; mktime()
将日历时间: struct tm
time_t
。
stdarg.h
用于实现可变参数函数
va_list
指向参数列表: 本质上是, char*
; va_start
初始化: 需要提供, va_list
; va_arg
得到列表的下一个变参值: 需要提供, va_list
; va_end
释放: 设为无效指针, 提供, va_list
。
典型的可变参数函数如printf()
printf()
1 | int printf(const char *format, ...); |
非标准库 (Nonstandard Library)
conio.h
回显getch()
而在_getch()
When reading a function key or an arrow key,
_getch()
must be called twice; the first call returns 0 or 0xE0, and the second call returns the actual key code.
io.h
io.h
_finddata_t
文件数据类型: ; attrib
文件属性: 如, _A_ARCH
(存档)、 _A_HIDDEN
(隐藏)、 _A_NORMAL
(正常)、 _A_RDONLY
(只读)、 _A_SUBDIR
(文件夹)、 _A_SYSTEM
(系统); size
以字节为单位的文件大小: ; name
文件名: ; time_create
文件创建时间: ; time_access
上次文件被访问时间: ; time_write
上次文件被修改时间: 。
_findfirst
获取第一个文件: 返回当前位置句柄, 需要提供路径字符串和指向, _finddata_t
; _findnext
获取下一个文件: 返回下一位置句柄, 需要提供当前位置句柄和指向, _finddata_t
; _findclose
释放: 提供句柄即可, 。
遍历目录下所有文件的代码如下
1 | intptr_t handle; |
windows.h
SetConsoleTextAttribute()
关于颜色的文本属性的解释
其中
, GetStdHandle(STD_OUTPUT_HANDLE)
用于获取标准输出句柄 。
1 | WORD attr = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE; |
若需获取控制台文本属性GetConsoleScreenBufferInfo()
1 | CONSOLE_SCREEN_BUFFER_INFO csbiInfo; |