C语言---一些特殊的用法(函数调度表、变量附加属性)
C语言
记录一些第一次见到感到奇怪(少见多怪)的C语句。编译器GNU gcc。
一、函数调度表
原理:定义特定格式的函数指针,再定义函数指针数组。然后把一个个函数指针(即函数名、函数地址),然后就可以像操控数组一样操控一堆函数了。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define pint(t) printf("the func is:%d\n",t);
void print1(int);
void print2(int);
void print3(int);
void print4(int);
typedef void(*print_fun)(int);
int main(void)
{
int i;
print_fun pointer_funs[4]={print1,print2,print3,print4};
for(i=0;i<4;i++)
{
pointer_funs[3-i](i);
}
return 0;
}
void print1(int a){
printf("hello,input %d :",a);
pint(1);
}
void print2(int a){
printf("hello,input %d :",a);
pint(2);
}
void print3(int a){
printf("hello,input %d :",a);
pint(3);
}
void print4(int a){
printf("hello,input %d :",a);
pint(4);
}
运行结果如图:

二、给定义的变量附加一些属性
原理:通过宏定义的方法,加上一些类别的属性。
注:
在用代码阅读工具,sourceinsight的时候,当出现了这样的代码。它会报Parse too Complex(语句太复杂,无法分析),把这里的宏定义当做函数,无法跳转。(不好用)
但是Scitool Understand就不一样了,直接自动把一些复杂的宏定义解析出来,解析出是变量的类型的定义而不是什么函数,阅读代码十分方便。(优点不止于此)
#include <stdio.h>
/* AUTOMATIC 用来声明本地指针 */
# define AUTOMATIC
/* TYPEDEF 应该用来声明类型定义*/
# define TYPEDEF
/* STATIC 编译器的关键字 */
# define STATIC static
/*
rettype : 返回的类型
ptrtype :指针的类型
type :类型
vartype :变量的类型
memclass: 所属的类别
ptrclass:指针的类别
*/
/* 函数返回变量类型 */
# define FUNC(rettype, memclass) memclass rettype
/* 函数返回指向const的指针类型 */
# define FUNC_P2CONST(rettype, ptrclass, memclass) const rettype ptrclass * memclass
/* 函数返回指针类型 */
# define FUNC_P2VAR(rettype, ptrclass, memclass) rettype ptrclass * memclass
/* 指针的类型 */
# define P2VAR(ptrtype, memclass, ptrclass) ptrtype ptrclass * memclass
/* 指向const的指针的类型 */
# define P2CONST(ptrtype, memclass, ptrclass) const ptrtype ptrclass * memclass
/* const指针的类型 */
# define CONSTP2VAR(ptrtype, memclass, ptrclass) ptrtype ptrclass * const memclass
/* 指向const的const指针的类型 */
# define CONSTP2CONST(ptrtype, memclass, ptrclass) const ptrtype ptrclass * const memclass
/* 指向函数的指针的类型 */
# define P2FUNC(rettype, ptrclass, fctname) rettype ( * ptrclass fctname)
/* const变量类型 */
# define CONST(type, memclass) memclass const type
/* 变量类型 */
# define VAR(vartype, memclass) memclass vartype
#define myCode_1
#define MAIN_C
FUNC(void,myCode_1) myCode_PrintFun( CONSTP2CONST(char,myCode_1,MAIN_C) );
int main(void)
{
myCode_PrintFun("abcdef");
return 0;
}
FUNC(void,myCode_1) myCode_PrintFun( CONSTP2CONST(char,myCode_1,MAIN_C) iString) {
printf("%s\n",iString);
}
运行结果如图:

三、结构体初始化
C语言标准用法
#include <stdio.h>
#define pint(a) printf("The int is:%d\n",a)
typedef struct{
int a;
int b;
}myStruct;
int main(void)
{
myStruct aTest[2]={
{
.a=555,
.b=666,
},
{
.a=333,
.b=444,
},
};
pint(aTest[0].a);
pint(aTest[0].b);
pint(aTest[1].a);
pint(aTest[1].b);
return 0;
}
运行结果如图:

四、结构体a.a 和 EOF
结构体标签和结构体变量同名
#include <stdio.h>
#include <string.h>
#define pint(t) printf("the int is %d\n",t);
struct a{ int a;};
struct a a;
int main(void)
{ a.a=1;
pint(a.a);
char c=EOF;
pint((int)c);
printf("The enum one is %c\n",c);
return 0; }
运行结果如图

参考:《C primer puls》,第14.10.5节
(略, C使用名空间这个词去识别部分的程序,其是名字识别的地方; 范围(scope)就是部分的概念:不同范围的同名变量同名不冲突,同范围会冲突 ; 名空间还有一种类别,结构体标签,union标签,枚举标签,它们在一个特殊的共享的名空间里,它们的名字不会与正常变量产生冲突; 就是标签名可以与变量名一样;。。。)C uses the term namespace to identify parts of a program in which a name is recognized. Scope is part of the concept: Two variables having the same name but in different scopes don’t conflict; two variables having the same name in the same scope do conflict. There also is a category aspect to namespaces. Structure tags, union tags, and enumeration tags in a particular scope all share the same namespace, and that namespace is different from the one used by ordinary variables. What this means is that you can use the same name for one variable and one tag in the same scope without causing an error, but you can’t declare two tags of the same name or two variables of the same name in the same scope. For example, the following doesn’t cause a conflict in C:
struct rect { double x; double y; };
int rect; // not a conflict in C(在C里面不会冲突,C++里面是不被允许的)
,
五、命令行参数与命令行文件输入输出
演示平台:windows10
工具链:
MinGWin:x86-gcc,此工具链适用于:编译环境(build)是x86,运行环境(host)是x86,属于本地编译(native compilation)。

5.1命令行参数演示代码:
默认第一个输入参数就是运行的文件名
#include <stdio.h>
int main(int argc,char** argv){
int i=1;
printf("the number of input para: %d,argv[0] is: %s\n",argc,argv[0]);
while( i<argc){
printf("The para numb :%d,is :%s\n",i,argv[i]);
i++; }
return 0; }
运行如图所以:
默认第一个是运行文件名,输入参数以空格分开,输入的是字符串

5.2命令行文件输入输出演示代码:
后续的补充:实际上,这里涉及到了操作系统的标准输入、标准输出、重定向(redirect)的内容。不同的操作系统都有各自的实现。
getchar()通过文件输入而不是屏幕;putchar()通过文件输出而不是屏幕。
#include <stdio.h>
int main(void){
char gets;
while( ( gets = getchar() ) != EOF){
putchar(gets); }
return 0; }
输入命令前:

输入后:

六、从初学者到对C语言的进一步的认识(End)
上面的记录都是本体在对C语言有一些熟悉时,所做的记录。具有片面与薄弱。本项记录,当做一个完结(仅仅是自我感想,记录时求快不求清晰不求准确,记录瞬时的本体想法)。
- 记录:在好几个月之前,我也许自认为对C语言是熟悉的。可这个熟悉站在更高的视角来看待,是狭隘的熟悉,不过是看过几本书,写过几百行代码,看过一些嵌入式的项目就满足了。实际上,我一没有系统的学习甚至是了解过计算机组成原理、操作系统、网络、编译器;二无实际动手完成一个简单的项目。永远活在Demo里,算得上什么熟悉呢?实际上:当从计算机组成上看,可以体会认识到C语言与CPU、计算机系统、机器代码、汇编语言之间的历史以及当前的紧密关联,C是站在它们之上的产物。当从操作系统的角度看待,操作系统是我们所用所得的应用的背后,之下级真像(本质),更能明白本质与C。我们所使用的C背后的本质是什么呢?。。。。。。
- 《Computer Systems A Programmer’s Perspective》,对于计算机这个学科。基础薄弱、经验浅显的本体而言,疏通了计算机的算术、CPU、IO、操作系统、编译、网络的庞大层次跨度,更是将不同层次间进行了一定的朔源探索、层级映射、关联外延。当配上了其可运行实例的讲解、问题与答案的检验、精心设计的实验,它就是一个对于初学者完美的构建(build)。当自我完成构建了这样的计算机基础的框架,可以更好地立足于计算机的世界,亦有着很多的路线可以继续深入构建!!!(阅读之前最好学会C语言,使用了很多C代码)
本体阅读的笔记:https://gitee.com/testzyh/notes/blob/master/%E8%BD%AC%E8%BD%BD%E4%B8%8E%E6%94%B6%E8%97%8F/%E6%96%87/Computer%20Systems%20A%20Programmer%E2%80%99s%20Perspective.md - 如果看完上面的基础书籍,再阅读《Operating Systems: Three Easy Pieces》、《操作系统导论》。则会十分轻松。(阅读之前最好学会C语言,使用了很多C代码)
笔记示意:
书籍信息:《Operating Systems: Three Easy Pieces》、《操作系统导论》
作者:REMZI H. ARPACI-DUSSEAU、ANDREA C. ARPACI-DUSSEAU、UNIVERSITY OF WISCONSIN–MADISON 译:王海鹏
时间:2014
参考书籍:
- 《Introduction to Computing Systems: From Bits and Gates to C andBeyond》,我们最喜欢的计算系统图书之一。它从晶体管开始讲解,一直讲到C。书中早期的素材特别好。
- 并发的文章《Cooperating Sequential Processes》,作者:Edsger Dijkstra。地址:https://www.cs.utexas.edu/users/EWD/transcriptions/EWD01xx/EWD123.html
参考概念:
- 同步原语(Synchronization primitives):http://www.cs.columbia.edu/~hgs/os/sync.html
本书实例的代码:GitHub:https://github.com/remzi-arpacidusseau/ostep-code
本书作业的代码:GitHub:https://github.com/remzi-arpacidusseau/ostep-homework
官网(导航):https://pages.cs.wisc.edu/~remzi/OSTEP/
阅读依赖:
操作系统导论:内存、将程序代码(从磁盘)加载到内存中、
关联:
用户希望执行某种特权操作:大多数操作系统提供几百个调用。POSIX标准
自我索引:
**堆**(概念):4.3节 。
本书范围之外的内容:
1、锁实现的硬件原语:我们需要硬件和操作系统的帮助来实现一个可用的锁。近些年来,各种计算机体系结构的指令集都增加了一些不同的硬件原语,我们不研究这些指令是如何实现的(毕竟,这是计算机体系结构课程的主题)