c语言实现库函数 c语言常用库函数含详细用法

C语言中重新实现库函数

fgets是从文件读取,getchar是从输入读取,两个还是有区别的

成都创新互联专注于网站建设|成都企业网站维护|优化|托管以及网络推广,积累了大量的网站设计与制作经验,为许多企业提供了网站定制设计服务,案例作品覆盖成都水泥搅拌车等行业。能根据企业所处的行业与销售的产品,结合品牌形象的塑造,量身定制品质网站。

怀疑是gets

如果一定要用fgets的话,那么可以先用freopen重定向输入,来使fgets和getchar的定向相同

以下用gets实现或者被实现

含测试函数main

#include stdio.h

int str_to_int(char *str)

{

int sign = 1;

int ret = 0;

char *p;

p = str;

if(*p == '+') p++;

else if(*p == '-') sign = -1, p ++;

while(*p)

{

if(*p = '0' *p = '9')

ret = ret * 10 + (*p - '0');

else break;

p ++;

}

return sign * ret;

}

int get_int_with_getchar()

{

char a[20] = {0};

int i = 0;

while(i19)

{

a[i] = getchar();

if(a[i] == '\n')

break;

i ++;

}

a[i] = 0;

return str_to_int(a);

}

int get_int_with_gets()

{

char a[20] = {0};

gets(a);

return str_to_int(a);

}

void gets_with_getchar(char *str)

{

int i = 0;

if(str == NULL) return;

do

{

str[i] = getchar();

}while(str[i++] != '\n' );

}

char *do_strchr(char *src, const char c)

{

char *p = src;

while(*p *p!= c) p ++;

if(*p != c) return NULL;

return p;

}

int do_isdigit(char c)

{

return c = '9' c = '0';

}

int do_isalpha(char c)

{

return (c = 'Z' c = 'A') || (c = 'z' c = 'a');

}

int main()

{

int a;

char test[100] ;

a = get_int_with_getchar();

printf("get_int_with_getchar = %d\n", a);

a = get_int_with_gets();

printf("get_int_with_gets = %d\n", a);

gets_with_getchar(test);

printf("gets_with_getchar = %s\n", test);

printf("do_strchr %s %s\n", do_strchr(test, 'a'), do_strchr(test, 'b'));

printf("do_isdigit = (%d,%d) \n", do_isdigit('1'), do_isdigit('a'));

printf("do_isalpha = (%d,%d) \n", do_isalpha('1'), do_isalpha('a'));

}

C语言:如何自己做库函数?

简单的一个例子,但是基本的程序编译的思想都在里面了,具体的需要你自己体会和查资料

跟着下面的步骤走

------------------------

第一步:我的电脑-属性-高级-环境变量

添加3个变量

1.名字:path 值:vc的安装目录里面包含cl.exe的bin目录路径+";"+vc目录下包含mspdb80.dll的目录的路径

比如我的是D:\Program Files\Microsoft Visual Studio 8\VC\bin;D:\Program Files\Microsoft Visual Studio 8\Common7\IDE;

2.名字:include 值:vc安装目录下的include目录,主要是为了找到头文件,我的是D:\Program Files\Microsoft Visual Studio 8\VC\include;D:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Include;

3.名字:lib 值:vc目录下包含库文件的目录路径

我的是D:\Program Files\Microsoft Visual Studio 8\VC\lib;D:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Lib;

第二步:需要下面两个文件

//-------------libdemo.c

#include stdio.h

void lib_func()

{

printf("this routine in lib\n");

}

//------------main.c

void lib_func();

int main(int argc, char *argv[])

{

lib_func();

}

第三步:命令

cl /c libdemo.c '编译libdemo.c 生成libdemo.obj

lib libdemo.obj '生成libdemo.lib 库文件

cl /c main.c '编译main.c

link main.obj libdemo.lib '生成main.exe

---------------------------------------------------

呵呵 加点东西,参看4楼的建议,在做个dll,COM组件就不做了,有点复杂了

1。把libdemo.c 稍微改下

//-------------libdemo.c

#include stdio.h

__declspec (dllexport) void lib_func()

{

printf("this routine in lib\n");

}

2。命令

cl /c libdemo.c main.c

link libdemo.obj /dll '生成libdemo.lib

link main.obj libdemo.lib

C语言库函数如何编写?

/***

*printf.c - print formatted

*

* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.

*

*Purpose:

* defines printf() - print formatted data

*

*******************************************************************************/

#include

#include

#include

#include

#include

#include

#include

/***

*int printf(format, ...) - print formatted data

*

*Purpose:

* Prints formatted data on stdout using the format string to

* format data and getting as many arguments as called for

* Uses temporary buffering to improve efficiency.

* _output does the real work here

*

*Entry:

* char *format - format string to control data format/number of arguments

* followed by list of arguments, number and type controlled by

* format string

*

*Exit:

* returns number of characters printed

*

*Exceptions:

*

*******************************************************************************/

int __cdecl printf (

const char *format,

...

)

/*

* stdout ''PRINT'', ''F''ormatted

*/

{

va_list arglist;

int buffing;

int retval;

va_start(arglist, format);

_ASSERTE(format != NULL);//断言宏。如果输出格式字符串指针为空,则在DEBUG版下断言,报告错误。

_lock_str2(1, stdout);

buffing = _stbuf(stdout);//stdout:指定输出到屏幕

retval = _output(stdout,format,arglist);

_ftbuf(buffing, stdout);

_unlock_str2(1, stdout);

return(retval);

}

以上为printf()的源代码

1、从含有可选参数函数中获得可选参数,以及操作这些参数

typedef char *va_list;

void va_start( va_list arg_ptr, prev_param );

type va_arg( va_list arg_ptr, type );

void va_end( va_list arg_ptr );

假定函数含有一个必选参数和多个可选参数,必选参数声明为普通数据类型,且能通过参数名来获得该变量的值。可选参数通过宏va_start、va_arg和va_end(定义在stdarg.h或varargs.h中)来进行操作,即通过设置指向第一个可选参数指针、返回当前参数、在返回参数后重新设置指针来操作所有的可选参数。

va_start:为获取可变数目参数的函数的参数提供一种便捷手段。设置arg_ptr为指向传给函数参数列表中的第一个可选参数的指针,且该参数必须是va_list类型。prev_param是在参数列表中第一个可选参数前的必选参数。

va_arg:返回由arg_ptr所指向的参数的值,且自增指向下一个参数的地址。type为当前参数的类型,用来计算该参数的长度,确定下一个参数的起始位置。它可以在函数中应用多次,直到得到函数的所有参数为止,但必须在宏va_start后面调用。

va_end:在获取所有的参数后,设置指针arg_ptr为NULL。

下面举例说明:

#include

#include

int average( int first, ... );

void main( void )

{

/* Call with 3 integers (-1 is used as terminator). */

printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );

/* Call with 4 integers. */

printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );

/* Call with just -1 terminator. */

printf( "Average is: %d\n", average( -1 ) );

}

int average( int first, ... )

{

int count = 0, sum = 0, i = first;

va_list marker;

va_start( marker, first ); /* Initialize variable arguments. */

while( i != -1 )

{

sum += i;

count++;

i = va_arg( marker, int);

}

va_end( marker ); /* Reset variable arguments. */

return( sum ? (sum / count) : 0 );

}

返回值为:

Average is: 3

Average is: 8

Average is: 0

综上所述,在printf()函数中,可以只输出一个字符串,也可按照一定的形式输出含有多个可选参数的字符串信息。因此,首先就要通过这些宏来获取所有的可选参数。在上面的源码可以看出printf()中,只使用了宏at_start,将可选参数的首地址赋给了arglist。

2、锁定字符串及输出字符串到屏幕

#define _lock_str2(i,s) _lock_file2(i,s)

void __cdecl _lock_file2(int, void *);

#define _unlock_str2(i,s) _unlock_file2(i,s)

void __cdecl _unlock_file2(int, void *);

int __cdecl _stbuf(FILE *);

void __cdecl _ftbuf(int, FILE *);

int __cdecl _output(FILE *, const char *, va_list);

在output函数中,读取格式字符串中的每一个字符,然后对其进行处理,处理方式根据每一个字符所代表的意义来进行,如:普通字符直接利用函数WRITE_CHAR(ch, charsout);输出到控制台。

其中的主要部分是对转换说明符(d,c,s,f)的处理,现在将对其中的部分代码进行详细说明,这里只说明最基本的转换说明符,对这些须基本的转换说明符进行修饰的修饰符,程序中单独进行处理。下面是函数output()(output.c)部分源代码:

case ST_TYPE:

//表示当前处理的字符的类型为转换说明符。

...

switch (ch) {

//下面对参数的获取都是利用宏va_arg( va_list arg_ptr, type );来进行的。

case ''c'': {

//从参数表中获取单个字符,输出到缓冲字符串中,此时,type=int

buffer[0] = (char) get_int_arg(argptr); /* get char to print */

text = buffer;

textlen = 1; /* print just a single character */

}

break;

case ''s'': {

//从参数表中获取字符串,输出到缓冲字符串中,此时,type=char*

int i;

char *p; /* temps */

text = get_ptr_arg(argptr);

...

}

break;

case ''w'': {

//对宽字符进行处理

...

} /* case ''w'' */

break;

...

case ''e'':

case ''f'':

case ''g'': {

//对浮点数进行操作

...

#if !LONGDOUBLE_IS_DOUBLE

/* do the conversion */

if (flags FL_LONGDOUBLE) {

_cldcvt((LONGDOUBLE*)argptr, text, ch, precision, capexp);

va_arg(argptr, LONGDOUBLE);

//对长双精度型进行处理,此时,type=long double

}

else

#endif /* !LONGDOUBLE_IS_DOUBLE */

{

//对双精度型进行处理,此时,type=double

_cfltcvt((DOUBLE*)argptr, text, ch, precision, capexp);

va_arg(argptr, DOUBLE);

}

...

break;

//对整型变量处理

case ''d'':

case ''i'':

...

goto COMMON_INT;

case ''u'':

radix = 10;

goto COMMON_INT;

case ''p'':

...

goto COMMON_INT;

case ''o'':

...

注:对于浮点型double和long double,有相应的转换说明符(%f表示双精度型,%lf表示长双精度型),而float却没有。其中的原因是,在KRC下,float值用于表达式或用作参数前,会自动转换成double类型。而ANSI C一般不会自动把float转换成double。有些程序已假定其中的float参数会被转换成double,为了保护大量这样的程序,所有printf()函数的float参数还是被自动转换成double型。因此,在KRC或ANSI C下,都无需用特定的转换说明符来显示float型。

综上所述,转换说明符必须与待打印字符的类型。通常,用户有种选择。例如,如要打印一个int类型的值。则只可以使用%d,%x或%o。所有这些说明符都表示要打印一个int类型的值;它们只不过提供了一个数值的几种不同表示。类似一,可以用%f、%g和%e来表示double类型的值。但如果转换说明与类型不匹配,将会出现意想不到的结果。为什么呢?问题就在于C向函数传递信息的方式。

这个失败的根本细节与具体实现相关。它决定了系统中的参数以何方式传递。函数调用如下:

float n1;

double n2;

long n3;

long n4;

...

printf("%ld,%ld,%ld,%ld",n1,n2,n3,n4);

这个调用告诉计算机,要把变量n1,n2,n3和n4的值交给计算机,它把这些变量放进称作栈(stack)的内存区域中,来完成这一任务。计算机把这些值放进栈中,其根据是变量的类型而不是转换说明符,比如n1,把8个字节放入栈中(float被转换成double),类似地,为n2放了8字节,其后给n3和n4各放了4个字节。接着,控制的对象转移到printf();此函数从栈中读数,不过在这一过程中,它是在转换说明符的指导下,读取数值的。说明符%ld指定printf()应读4个字节(va_arg( va_list arg_ptr, type )中type=long),因此printf()读入栈中的4个字节,作为它的第一个值。但是这只是n1的前半部分,这个值被看成一个long整数。下一个说明符%ld读入4个字节,这正是n1的后半部分,这个值被看成第二个long整数。类似地,第三、第四次又读入n2的前后两部分。因此,尽管我们对n3和n4使用了正确的说明符,printf()仍然会产生错误。

C语言 库函数的实现???

C语言的库函数大多数是用C语言编的,只有少数与硬件有直接联系的核心部分才用汇编.

所谓库函数并不深奥,库函数也是由一个一个函数(子程序)组成的,如同我们自己程序里,有时也写很多子程序.

如果我们把一些可以反复使用的子程序拿出来,集中到一起,编译成一个my.obj文件,今后写新程序时我们不另写这些子程序,我们只写子程序的调用语句,编译时链结my.obj就可以了.当然,新程序的main()前面要有这些被调函数(子程序)的"原型"声明.

my.obj加上它里面的函数"原型"声明,就构成了库函数.函数"原型"声明就是这个库的"头"文件-- my.h, 这就是静态链结库.

自己也可以写动态链接库,动态链接库包括.DLL,.LIB,.H

自己写的静态链结库和动态链接库也可给别人用.就象C语言的库函数给你用一样.当你给别人时,你如果不给你写的C的函数,别人也"看不到了",别人只能查头文件,得知函数名,参数个数和类型.


网页名称:c语言实现库函数 c语言常用库函数含详细用法
文章出自:http://ybzwz.com/article/doeeiip.html