各种糟糕,入坑这么久才开始看K&R的The C Programming Language学C,而且还是为了应付开学某场滚回本体的考试(虽然觉着即使复习了还会被各种吊打),废话不多说,开始施工.
|-->
关键字 |
位长(字节) |
范围 |
格式化字符串 |
char |
1 bytes |
-128..127(或0..255,与体系结构相关) |
%c |
unsigned char |
1bytes |
0..255 |
%c, %hhu |
signed char |
1bytes |
-128..127 |
%c, %hhd, %hhi |
int |
2bytes(16位系统) |
-32768..32767 |
%i, %d |
4bytes |
-2147483648..2147483647 |
||
unsigned int |
2bytes |
0..65535 或 |
%u |
4 bytes |
0..4294967295 |
||
signed int |
2bytes |
-32768..32767 |
%i, %d |
4bytes |
-2147483648..2147483647 |
||
short int |
2bytes |
-32768..32767 |
%hi, %hd |
unsigned short |
2 bytes |
0..65535 |
%hu |
signed short |
2bytes |
-32768..32767 |
%hi, %hd |
long int |
4bytes |
-2147483648..2147483647 |
%li, %ld |
8bytes |
-9223372036854775808..9223372036854775807 |
||
unsigned long |
4bytes |
0..4294967295 或 |
%lu |
8 bytes |
0..18446744073709551615 |
||
signed long |
4 bytes |
-2147483648..2147483647 或 |
%li, %ld |
8bytes |
-9223372036854775808..9223372036854775807 |
||
long long |
8bytes |
-9223372036854775808..9223372036854775807 |
%lli, %lld |
unsigned long long |
8bytes |
0..18446744073709551615 |
%llu |
float |
4bytes |
3.4x10−38..3.4x10+38 (7 sf) |
%f, %e, %g |
double |
8bytes |
1.7x10−308..1.7x10+308 (15 sf) |
%lf, %e, %g |
long double |
8 bytes或以上 |
编译器相关 |
%Lf, %Le, %Lg |
整数除法会截断结果中的小数部分(向零取整,truncate towards 0),故先乘后除. 在有负操作数的情况下,整数除法截取的方向以及取模运算结果的符号取决于具体机器的实现,这和处理上溢或下溢的情况是一样的,可以保证的是 (x / y) * y + ( x % y) == x. (C99明确a / b、a % b结果正负与a相同)
当把float转换为int时小数部分会被截断,float转换为double时截断还是四舍五入取决于具体实现(待补CSAPP).
1UL < -1L < 1U
对于expr1 ? expr2 : expr3,若expr2、expr3类型不同,结果类型由类型转换规则决定.
()、 []、 -> 、 . |
圆括号、方括号、指针、成员 |
++ 、 -- 、 * 、 & 、 ~ 、 ! 、 + 、 - 、 sizeof、(type) |
单目运算符(右结合) |
* 、 / 、 % |
算术运算符 |
+ 、 - |
算术运算符 |
<< 、 >> |
位运算符 |
< 、 <= 、 > 、 >= |
关系运算符 |
== 、 != |
关系运算符 |
& |
位与 |
^ |
位异或 |
| |
位或 |
&& |
逻辑与 |
|| |
逻辑或 |
? 、 : |
条件运算符 |
= 、 += 、 -= 、 *= 、 /= 、 %= 、 &= 、 |= 、 ^= |
赋值运算符(右结合) |
, |
顺序(逗号)运算符(右结合) |
除&&、||、,(逗号运算符)外C语言没有指定同一运算符多个操作数的计算顺序,以及函数各个参数的求值顺序.
全局变量作用于所有源文件,但如果要在不包含该定义的源文件中引用,需要在所引用的源文件中声明为extern;
静态全局变量仅仅作用于所在源文件。
补充:
未初始化的全局变量存储在bss段 (Block Started by Symbol);
已初始化且不为0的全局变量存储在数据段(Data Segment)。
由于右结合性,*p++ ó *(p++) ,故若要表示 *p += 1 应写为 (*p)++。
注意指针是一个变量,而数组名不是变量;
在函数定义中,形参 char s[] 与 char s[] 等价。
一个用法:
void strcpy(char *s, char *t)
{
while(*s++ = *t++);
}
*p++ = val;
val = *--p;
f(arr[i][j]) ó f(arr[][j]) ó f((*arr)[j]) //I, j 为常量
char *name[] = {"Link", "Zelda", "Rauru", "Fado"};
K&R C为此直接写了一个Parser @_@ 私以为还是遵循"从内往外,从右往左"的读法。(参考 Clockwise/Spiral Rule )
sizeof <object name> or sizeof(<type name>)
#if 中不能使用 sizeof,因为预处理器不对类型名进行分析。而预处理并不计算#define中的表达式,所以在其中可以合法使用sizeof。
设low=&a[0]、high=&a[n]分别表示指向表头、表尾元素的指针,则下面表达式无法计算中间元素位置:
mid = (low+high) / 2 /* wrong*/
原因是两个指针间加法是非法的,而减法是合法的,正确表达如下:
mid = low + (high-low) / 2
结构体的长度不一定等于各成员长度之和,与内存对齐要求有关。
struct S { // will usually occupy 8 bytes: // 5 bits: value of b1 // 27 bits: unused // 6 bits: value of b2 // 15 bits: value of b3 // 11 bits: unused unsigned b1 : 5; unsigned :0; // start a new unsigned int unsigned b2 : 6; unsigned b3 : 15; }; /* 摘自: http://en.cppreference.com/w/c/language/bit_field */
e/f/g 对printf来说指 double 类型(变长参数中float会提升为double);对scanf来说指 float* 类型,le/lf/lg 指double* 类型.
注意:
gets在读取字符串时将删除结尾'\n',puts再写入字符串时则会添加'\n'.
int getchar(); int putchar(int); printf(const char * format, ...); scanf(const char * format, ...); / * 文件操作 */ int getc(FILE *fp); int putc(int c, FILE *fp); int fscanf(FILE *fp, char *format, ...); int fprintf(FILE *fp, char *format, ...); int fclose(FILE *fp); int ferror(FILE *fp); int feof(FILE *fp); char *fgets(char *line, int maxline, FILE *fp); int fputs(char *line, FILE *fp);
暂时不管(从这强行跳票 = ,=
有些挺有用的,以后碰到再做补充.
#include <stdarg.h>
va_list ap;
va_start(ap, lastarg);
Type value = va_arg(ap, Type);
va_end(ap);
<--|
具体参考 C99
懒得搬运了
(Finished@2016/2/1)