c语言函数封装原理 c语言怎样将程序进行函数封装

封装性只对面向对象编程而言的吗?难道C不是吗?C语言也分函数块儿呢...不严格来说,函数也具有封装性 , 但它是对功能的封装,而面向对象是对数据的封装 , 具有更高的内聚度,内聚度是指一个模块内部各成份的联系 。C 把函数和数据分开了,以数据的观点来看C语言的封装内聚度很低,几乎等于零了,而我们想要封装的数据,所以一般我们说封装性都是说面向对象语言的
C语言中如何将自己常用的函数封装到编译器的库函数中具体应该怎么做呢?用编译器提供的库管理工具 。
C语言的编译器都会提供一个命令行工具,可以把自己编译后的.obj模块加入指定的库文件,以后使用时只需要连接该库文件即可 。这个命令行工具通常是lib.exe,用这个工具可以查看库中的模块,可以把模块加入到库中,可以从库中删除模块 。这个工具不仅仅是自己建立的库文件的管理工具,可以管理所有的库文件,包括C语言提供的标准库 。
c#中为什么采用c语言封装1基本概念
1.1对象[1]
对象是人们要进行研究的任何事物,从最简单的整数到复杂的飞机等均可看作对象,它不仅能表示具体的事物,还能表示抽象的规则、计划或事件 。
对象具有状态,一般用数据值来描述它的状态 。
对象还有操作 , 用于改变对象的状态,对象及其操作就是对象的行为 。
对象实现了数据和操作的结合,使数据和操作封装于对象的统一体中 。
1.2面向对象
简而言之,面向对象就是把客观存在或主观抽象的事物(即对象)抽象成类 。
所谓抽象就是去异求同 , 从众多的事物(即对象)中抽取出共同的、本质性的特征,舍弃其非本质的特征 。比如香蕉、苹果、哈密瓜等 , 它们共同的特性就是水果 。得出水果概念的过程就是一个抽象的过程 。在抽象时 , 同与不同,取决于从什么角度上来抽象 。抽象的角度取决于分析问题的目的 。
具有相同特性(数据元素)和行为(功能)的对象的抽象就是类 。因此,对象的抽象是类 , 类的具体化就是对象,也可以说类的实例是对象 。
1.3类
面向对象有三大特性:封装、继承、多态 , 这些特性主要通过类来体现 。类就是一个封装了属性以及相关操作的代码的逻辑实体 。
类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性 。
类具有方法,它是对象的行为的抽象 , 用方法名和实现该操作的方法来描述 。
除了封装属性和操作外,类还具有访问控制的功能,比如,某些属性和方法可以是私有的,不能被外界访问,通过访问控制 , 能够对内部数据提供不同级别的保护,以防止外界意外地改变或使用了私有部分 。不同的编程语言提供的访问控制等级不尽相同,但都有公有、私有两个等级 。
类是抽象的数据类型,在内存中并不存在(Python等动态语言除外) , 只有类的实例存在于内存中 。
2UML类图
在面向对象设计开发中,通常使用UML工具来进行分析设计 。比如,可以使用UML类图来描述类 。
UML类图很简单,用一个矩形框代表一个类,矩形框内部被隔为三部分:上面部分为类的名字,中间部分为类的属性,下面部分为类的方法 。对于属性和方法,还可以使用“ ”、“-”修饰符来表示访问权限,“ ”为公有属性、“-”为私有属性 。
如图1所示,该类图描述了一个名为“Human”的类 。“Human”类抽象并封装了“人”;属性“name”是对人姓名的抽象,因为人的姓名是公开的,所以被设置为公有属性;属性“money”是对人所拥有的财富的抽象,因为每个人的财富都不是公开的,所以被设置为私有属性;方法“buy”是对购物这一行为的抽象 , 方法“talk”是对讲话这一行为的抽象,这两个方法都是社会活动,所以被设置为公有属性 。
?
设计类的过程就是抽象的过程,抽象的结果取决于抽象时所站的角度,比如 , 如果是警察来抽象“Human”,他可能会添加一个“isBadGuy”属性 。
UML类图主要用于辅助分析和设计阶段,在设计类时应聚焦在与当前问题有关的重要属性和行为,无关的属性和方法统统去掉 , 确保UML类图是简洁有效的 。除非私有属性或方法会影响到问题的理解或者类的实现,否则UML类图中不要出现私有属性和方法,私有属性通常在实现阶段才会去考虑 。
UML类图以及其他UML元素都是辅助软件开发的工具 , 使用UML进行设计时 , 只要相关人员能够通过UML图看懂你的设计、不妨碍沟通就可以了,即使用草稿纸来作图也是可以的,所以,不用太过纠结那些细节 , 且一定要避免过度设计 。
3C语言的类封装实现
很多现代编程语言都有原生的面向对象支持 , 比如C、JAVA、Python等,这些编程语言提供了class数据类型,在这些编程语言中类实际上就是一种数据类型,因此能够更好地支持面向对象编程 。
实际上,面向对象是与编程语言无关的,更像是一种思想 , 且不局限于软件开发活动,任何需要分析解决问题的场合都可以使用面向对象 。
C语言并没有类的概念,但是可以从类的特性出发,利用C语言的某些特性来实现类的用法 。关于类,首先要解决的就是封装问题 , 类的封装特性需要能够封装属性和方法,还要有访问控制 。可以使用.h、.c文件和结构体来完成封装 。
下面以图1中Human类的C语言实现为例来叙述C语言的类封装问题,本文使用human.h、human.c、struct human三个元素来完成封装,human.c为human.h中函数声明的实现,本文不讨论这些细节 , 所以只给出human.h的关键代码片段,如下所示:
typedef struct human {
const char *name;
int _money;
} human_t;
human_t *human_init(human_t *p_this, const char *name, intmoney);
voidhuman_talk(human_t*p_this, const char*p_words);
voidhuman_buy(human_t*p_this, const char *p_something, unsignedprice, unsignedcount);
voidhuman_deinit(human_t *p_this);
(1)类名
Human类的名称体现在human.c、human.h以及human.h中所有全局符号的命名上 , 这些命名全部使用关键字human作为前缀 。
(2)属性
Human类的属性体现在自定义类型human_t中 , human_t实际上为结构体struct human,它有两个成员:name和_money,分别对应类图中的属性 name和-money , 特别留意_money成员前的“_”,这是为了警示类的使用者“此成员为私有属性,不可使用” 。
(3)方法
Human类的方法体现在human_talk()、human_buy()这两个函数上,分别对应类图中的方法 buy()和 talk() 。此外,还可以注意到有human_init()、human_deinit()这两个函数,分别为Human类的构造、析构方法 。构造、析构方法分别用于类对象的初始化和解初始化 。
构造函数human_init()需要用户提供Human对象的内存,通过第一个参数p_this传递 , 对象的内存等价于一个human_t变量 。
C语言中可以使用C文件中的static函数实现私有方法,假如Human类有私有方法money_pay(),则其C语言实现如下:
// human.c
static int __human_money_pay (human_t *p_this, unsignedcost)
{ … }
UML类图中一般不会显式地出现构造、析构和私有这三种方法,除非需要在类的构造、析构和实现上有特殊说明 。
另外需要注意的是,这几个方法函数的第一个参数都是human_t *类型,且名称为p_this,这是C语言面向对象编程与面向过程的最大不同:p_this为指向类实例(即对象)的指针 , 所有的方法操作都需要“针对”一个对象,p_this指针由类的构造函数返回,比如,human_init()构造一个Human实例,然后返回指向此实例的p_this指针 , 然后就可以调用human_talk(p_this, …)等方法对实例进行操作 。
(4)访问控制
在Human类的C语言实现中,属性被定义为human_t中的两个成员,而 human_t被定义在用户可见的human.h中,所以human_t是暴露给用户的,因此,从语法上讲,Human类的两个属性是暴露给用户的,即都是公有属性 。虽然语法上不能支持私有,但可以在编程规范上设定“私有属性以短下划线“_”开头”,比如“_money”,如此从某种意义上实现了属性的访问控制 。
在Human类的C语言实现中 , 方法被定义为human.c中的函数 。公共方法对应的函数都没有“static”关键字,且在human.h中有对应的函数声明 。而私有方法对应的函数都有“static”关键字 , 这些私有方法只能在human.c文件内部调用,对用户不可见 。由此可知,C语言本身就能支持方法的访问控制 。
4结论
本文通过使用C语言实现一个Human类,讨论了如何使用C语言来实现类的封装特性 。在C等面向对象语言中 , 使用class对类做了原生的支持,使用起来非常简单 。尽管C语言并不是原生支持类,但通过语言、概念、规范上的处理,也能实现类的封装特性 。用C语言实现类的封装相当于解决了C面向对象的关键第一步,在其基础之上可以引入更多现代软件方法 。
参考文献
[1] 百度. 百度百科/面向对象[EB/OL].[2016-08-08]. SX7EjstoDVm wJ13OAod XUrUrnZkVg3ntPFir Ey5c6mqObZZ OevQI6K3Ungq1Mq.
c语言中可封装指啥 c语言中可封装的意思1、c语言封装:一个结构体,所有函数共同组成的整体中结构体定义为全部变量,可以实现C版得继承和封装,但不能实现多态 。
2、封装:将类的成员定义成私有的 。这样对象的外部,无法直接调用这些私有的字段和方法 。需要封装是因为私有的方法、字段只有类的内部可以访问,因此,如果类的编写者随意修改它们的名字,增加删除私有成员 , 肯定不会需要调用这个类的所有人修改他们各自的调用方法,程序仍然可以执行 。因此,封装后,类的所有者可以在不改变类的外观的情况下更改内部的设计、优化程序的效率和修改BUG 。
C语言封装与分离是怎么的概念 尽量具体点主要是函数的定义和调用要分开 。
就是不能在同一个源文件中定义所有的函数,特别是程序代码特别多的时候 。可以将函数的定义放在其他源文件中,只在main函数所在的文件中调用(记得包括相对应的头文件,并声明函数) 。这样一来,他人或自己在对读程序或修改的时候 , 就容易的多 。只要逐项检查每个函数 , 以及调用过程中的逻辑顺序就可以简单定位出程序的错误 , 或对某些函数处理进行修改 。
C语言怎么封装自己写的函数用C语言c语言函数封装原理的时候,您是否还在使用printf函数来输出日志呢?您是否考虑过将printf函数打印的内容存到文件中去呢?您是否想拥有一个可选择的既支持输出到屏幕又支持存储到文件中的日志函数呢?很高兴的告诉您,如果您愿意的话,欢迎使用本人编写的一个一套日志函数,该套函数由五部分组成 , 分别是宏变量BUF_SIZE、结构体log_st、log_init函数、log_debug函数和log_checksize函数 。其中宏变量BUF_SIZE用来限制每次输出的日志的最大长度c语言函数封装原理;结构体用来存储用户需求,包括文件路径、文件描述符号、单个文件最大大小、输出方式标志、文件命名标志等;log_init函数用来完成用户需求录入、文件创建等功能,在mian函数的开始调用一次即可;log_debug函数的功能跟printf很类似,是在printf基础上进行的扩充,实现将日志输出到屏幕或者写入到文件,在需要打印日志的地方调用该函数;log_checksize函数用来检测日志文件大小是否超过最大大小限制,它需要您定时或者定点调用它 , 如果一直不调用,则日志文件将不受指定的最大大小限制 。
一、定义宏变量BUF_SIZE
view plaincopy to clipboardprint?
#define BUF_SIZE 1024
二、定义log_st结构体
view plaincopy to clipboardprint?
typedef struct _log_st log_st;
struct _log_st
{
char path[128];
int fd;
int size;
int level;
int num;
};
三、定义log_init函数
【c语言函数封装原理 c语言怎样将程序进行函数封装】参数说明:path——您要存储的文件路径;size——单个文件的最大大?。?如果超过该大小则新建新的文件用来存储;level——日志输出方式 , 建议在上层限制其值的范围为0到3,0表示日志既不输出到屏幕也不创建文件和保存到文件,1表示日志保存到文件但不输出到屏幕 , 2表示日志既输出到屏幕也保存到文件,3表示日志只输出到文件而不创建文件和存入文件;num——日志文件命名方式 , 非0表示以(int)time(NULL)作为文件名来保存文件,文件数量随着日志量的递增而递增;0表示以“.new”和“.bak”为文件名来保存文件 , 文件数量不超过两个,随着日志量的递增,旧的日志文件将被新的覆盖,更直观的说就是说.new”和“.bak”文件只保存最近的日志 。
view plaincopy to clipboardprint?
log_st *log_init(char *path, int size, int level, int num)
{
char new_path[128] = {0};
if (NULL == path || 0 == level) return NULL;
log_st *log = (log_st *)malloc(sizeof(log_st));
memset(log, 0, sizeof(log_st));
if (level != 3)
{
//the num use to control file naming
log-num = num;
if(num)
snprintf(new_path, 128, "%s%d", path, (int)time(NULL));
else
snprintf(new_path, 128, "%s.new", path);
if(-1 == (log-fd = open(new_path, O_RDWR|O_APPEND|O_CREAT|O_SYNC, S_IRUSR|S_IWUSR|S_IROTH)))
{
free(log);
log = NULL;
return NULL;
}
}
strncpy(log-path, path, 128);
log-size = (size0 ? size:0);
log-level = (level0 ? level:0);
return log;
}
四、定义log_debug函数
view plaincopy to clipboardprint?
void log_debug(log_st *log, const char *msg, ...)
{
va_list ap;
time_t now;
char *pos;
char _n = '\n';
char message[BUF_SIZE] = {0};
int nMessageLen = 0;
int sz;
if(NULL == log || 0 == log-level) return;
now = time(NULL);
pos = ctime(now);
sz = strlen(pos);
pos[sz-1]=']';
snprintf(message, BUF_SIZE, "[%s ", pos);
for (pos = message; *pos; pos);
sz = pos - message;
va_start(ap, msg);
nMessageLen = vsnprintf(pos, BUF_SIZE - sz, msg, ap);
va_end(ap);
if (nMessageLen = 0) return;
if (3 == log-level)
{
printf("%s\n", message);
return;
}
if (2 == log-level)
printf("%s\n", message);
write(log-fd, message, strlen(message));
write(log-fd, _n, 1);
fsync(log-fd);
}
五、定义log_checksize函数
view plaincopy to clipboardprint?
void log_checksize(log_st *log)
{
struct stat stat_buf;
char new_path[128] = {0};
char bak_path[128] = {0};
if(NULL == log || 3 == log-level || '\0' == log-path[0]) return;
memset(stat_buf, 0, sizeof(struct stat));
fstat(log-fd, stat_buf);
if(stat_buf.st_sizelog-size)
{
close(log-fd);
if(log-num)
snprintf(new_path, 128, "%s%d", log-path, (int)time(NULL));
else
{
snprintf(bak_path, 128, "%s.bak", log-path);
snprintf(new_path, 128, "%s.new", log-path);
remove(bak_path); //delete the file *.bak first
rename(new_path, bak_path); //change the name of the file *.new to *.bak
}
//create a new file
log-fd = open(new_path, O_RDWR|O_APPEND|O_CREAT|O_SYNC, S_IRUSR|S_IWUSR|S_IROTH);
}
}
c语言函数封装原理的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于c语言怎样将程序进行函数封装、c语言函数封装原理的信息别忘了在本站进行查找喔 。

    推荐阅读