《你必须知道的495个C语言问题》知识笔记及补充
1. extern在函数声明中是什么意思?
它可以用作一种格式上的提示表明函数的定义可能在另一个源文件中,但在
extern int f(); 和 int f(); 之间并没有实质的区别。
补充:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。此外extern也可用来进行链接指定。也就是说extern有两个作用:
第 一,当它与"C"一起连用时,如: extern "C" void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的,C++的规则在翻译这个函数名时会把fun这个名字变得面目 全非,可能是fun@aBc_int_int#%$也可能是别的,这要看编译器的"脾气"了(不同的编译器采用的方法不一样),为什么这么做呢,因为 C++支持函数的重载;
第二,当extern不与"C"在一起修饰变量 或函数时,如在头文件中: extern int g_Int; 它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块活其他模块中使用,记住它是一个声明不是定义!也就是 说B模块(编译单元)要是引用模块(编译单元)A中定义的全局变量或函数时,它只要包含A模块的头文件即可,在编译阶段,模块B虽然找不到该函数或变量, 但它不会报错,它会在连接时从模块A生成的目标代码中找到此函数。
2. 怎样建立和理解非常复杂的声明?例如定义一个包含N个指向返回指向字符的指针的函数的指针的数组?
这个问题至少有以下3种答案:
(1)char *(*(*a[N])())();
(2)用typedef逐步完成声明:
1
2
3
4
5
6
|
typedef
char
*pc;
/* 字符指针 */
typedef
pc fpc();
/* 返回字符指针的函数 */
typedef
fpc *pfpc;
/* 上面函数的指针 */
typedef
pfpc fpfpc();
/* 返回函数指针的函数 */
typedef
fpfpc *pfpfpc;
/* 上面函数的指针 */
pfpfpc a[N];
/* 上面指针的数组 */
|
(3)使用cdecl程序,它可以把英文翻译成C或者把C翻译成英文:
通过类型转换,cdecl也可以用于解释复杂的声明,指出参数应该进入哪一对括号(如同在上述的复杂函数定义中)。
补充:cdecl程序非常有用,它可以在C语言的声明和英语之间进行转换。它可以解释一个现存的C语言声明,cdecl 程序可以帮助你分析复杂的声明。
这里有一个在线的cdecl:一个在线的cdecl.
3. 为什么struct x { ... }; x thestruct; 不对?
C不是C++。结构标签不能自动生成类型。
补充:也就是在C++中这样是对的。在C中不想用struct只能借助于typedef。
4. NULL可以确保是0,但空指针(null)却不一定。
5. 数组和指针的区别是什么?
如果你向函数传递二维数组:
在第一个声明中,编译器进行了通常的从“数组的数组”到“数组的指针”的隐式转换;第二种形式中的指针定义显而易见。
1
2
3
|
char
*str;
gets
(str);
printf
(
"%s\n"
, str);
|
改正方法:用局部变量或用malloc()分配str缓冲区。
1
2
3
4
5
6
|
char
*itoa(
int
n)
{
char
retbuf[20];
// error
sprintf
(retbuf,
"%d"
, n);
return
retbuf;
// error
}
|
一种解决方案是把返回缓冲区声明为静态变量:
总结:若要返回字符串或其它集合,则返回指针必须是静态分配的缓冲区,或者调用者传入的缓冲区,或者用malloc()获得的内存,但不能是局部(自动)数组。
补充:free()过后的指针也叫做“ 野指针”,建议free()过后立即将指针置为NULL,详细原因请看“ 为什么free(re)过后re不为NULL呢?”。
1
2
|
p =
malloc
(m * n);
memset
(p, 0, m * n);
|
13. C语言中没有提高标准的布尔类型,需要用#define或枚举常数定义true/false。
1
2
3
4
|
#define Str(x) #x
#define Xstr(x) Str(x)
#define OP plus
char
*opname = Xstr(OP);
|
总结:在使用符号粘接操作符##连接两个宏的值(而不是名字)时也要采用同样的“迂回战术”。
而memcpy()则不能提供这样的保证,因此可以实现的更加有效率。
如果有疑问,最好使用memmvoe()。
1
|
#define isnan(x) ((x) != (x))
|
1
2
3
4
5
|
int
x = 1;
if
(*(
char
*)&x == 1)
printf
(
"little-endian\n"
);
else
printf
(
"big-endian\n"
);
|
1
2
3
4
5
6
|
int
dayofweek(
int
y,
int
m,
int
d)
/* 0 = Sunday */
{
static
int
t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
return
(y + y/4 - y/100 + y/400 + t[m - 1] + d) % 7;
}
|