c grammar review

review the grammar of c programming language and take some notes

.h文件中的预处理操作

主要参考资料是这个,需要弄清楚的问题:

1 预处理在整个编译过程的哪一步,由谁对谁进行预处理?
2 预处理的功能主要分成哪些?
3 定义constant的关键语法是什么
4 conditional compilation的key word还有具体情况下如何生效,每种情况的具体含义是什么(comment out code,include guard)
5 macro定义需要主要的地方,与function call的区别在哪里,使用macro需要特别注意的地方是什么。

#include

paste the text of the given file into the current file

#define与#undefine

#undefused to scope a preprocessor constant into a very limited region–this is done to avoid leaking the constant, preprocessor does not understand block scopes defined with { and }

#if,#elsif,#endif 按照常用的if的逻辑进行流程控制。更具体一点,#if用于检查后面的变量是否为true,#ifdef <token>用于检查是否<token>的位置的信息在前面的文件中被#define过。比如可以使用如下的代码判断是c++的场景还是c的场景:

1
2
3
4
5
#ifdef __cplusplus
// C++ code
#else
// C code
#endif

#ifndef是和上面相反,用于判断后面的statement是否存在,如果不存在,则往后执行,如果存在则直接到#endif的那句话。长使用的情况如下:

1
2
3
#ifndef _INCL_GUARD
#define _INCL_GUARD
#endif

如果在之前没有define constant,则执行define操作,常常用于define guard的操作。

#error后面的内容表示发生编译错误的时候,后面的内容会显示出来,比如类似如下的操作:

1
2
3
#ifndef __unix__ // __unix__ is typically defined when targetting Unix
#error "Only Unix is supported"
#endif

如果不是unix的系统,就没有unix的macro定义,在编译的时候就会报error出来。

几个经常会用到的macro:

1
2
3
4
5
__FILE__
__LINE__
__DATE__
__TIME__
__TIMESTAMP__

具体这几个macro定义的用法可以通过以下例子来展示,主要是在日志输出的时候比较容易使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# include <stdio.h>
int logError (const char* file, const int line, const char* message)
{
printf("file (%s) , line (%d), date (%s), time (%s), timestamp (%s), output message (%s)\n", file,line,__DATE__ ,__TIME__,__TIMESTAMP__,message);
return 0;
}
int main(int argc, char const *argv[])
{
/* code */
printf("%s\n", "macro test" );
logError(__FILE__,__LINE__,"error message");
return 0;
}
/*output:
macro test
file (testmacro.c) , line (14), date (Aug 30 2017), time (22:08:25), timestamp (Wed Aug 30 22:08:23 2017), output message (error message)
*/

其他不熟悉的关键字 感觉整理了好多次了

static

1) static 类型的变量长驻内存 普通的变量会随着调用函数的结束而销毁 A static int variable remains in memory while the program is running. A normal or auto variable is destroyed when a function call where the variable was declared is over.

比如可以利用这个特性计算某个函数的被调用次数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
int fun()
{
static int count = 0;
count++;
return count;
}
int main()
{
int i=0;
for(i=0;i<3;i++){
printf("%d\n",fun());
}
return 0;
}
/*output
1
2
3
*/

2) 在c中,函数默认是全局可见的,如果在函数的前面使用了static的标志,函数会变成在本文件的范围内可见,比如file2.c中引用了file1.c中的static类型的函数,那么在编译的时候就会出现错误,类似“undefined reference to `fun1’”。

const

类型修饰的一部分,无法被修改。

主要需要了解const char* p(指针本身是const的)与char* const p(指向常量的指针)的区别。

extern

基本描述,在一个文件中使用extern进行声明的变量或函数表示:改变量或函数在其他文件中有进行定义,编译器会到其他模块中寻找对应的部分然后进行编译。

这一篇中包含了static, const, 以及extern的区别。

typedef

typedef的常见用法与陷阱,具体看这个

assert

主要是说括号中的逻辑为0,也就是为false的话,首先会向stderr打印一条错误信息,之后程序会终止运行。具体更多的细节可以参考网上的相关资料。

attribute

具体可以参考以下资料,__attribute__机制大致就是说在编译器进行编译的过程中可以将一些操作告知compiller使起进行一些额外的操作。attribute机制不是c语法的一部分,是GNU对于C进行的扩展。

https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes

http://unixwiz.net/techtips/gnu-c-attributes.html

https://stackoverflow.com/questions/4223367/how-to-use-the-attribute-keyword-in-gcc-c

reference

《c programming language》

c_book

gnu c manual

memory layout of c program

一个在线的ide 可以用来运行一些简单的测试

很棒的c资料 讲解很系统

make file simple tutorial 从最简单到很复杂的书写过程

make file detailed tutorial

gcc and make

编写make文件的时候利用gcc处理依赖关系

#include时候的引用关系