c库函数源码
发布网友
发布时间:2022-04-24 02:48
我来回答
共5个回答
热心网友
时间:2023-10-22 20:24
不是你表达不清,也许只是你根本不想仔细看一睛VC下面目录的源码,事实上就是有的。后附其中的qsort.c,以证明所言不虚。
VC的库是提供源码的,这东西也不值钱。
X:\Program Files\Microsoft Visual Studio\VCXX\CRT\SRC
注意有些可能本身是用汇编写的。
/***
*qsort.c - quicksort algorithm; qsort() library function for sorting arrays
*
* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* To implement the qsort() routine for sorting arrays.
*
*******************************************************************************/
#include <cruntime.h>
#include <stdlib.h>
#include <search.h>
/* prototypes for local routines */
static void __cdecl shortsort(char *lo, char *hi, unsigned width,
int (__cdecl *comp)(const void *, const void *));
static void __cdecl swap(char *p, char *q, unsigned int width);
/* this parameter defines the cutoff between using quick sort and
insertion sort for arrays; arrays with lengths shorter or equal to the
below value use insertion sort */
#define CUTOFF 8 /* testing shows that this is good value */
/***
*qsort(base, num, wid, comp) - quicksort function for sorting arrays
*
*Purpose:
* quicksort the array of elements
* side effects: sorts in place
*
*Entry:
* char *base = pointer to base of array
* unsigned num = number of elements in the array
* unsigned width = width in bytes of each array element
* int (*comp)() = pointer to function returning analog of strcmp for
* strings, but supplied by user for comparing the array elements.
* it accepts 2 pointers to elements and returns neg if 1<2, 0 if
* 1=2, pos if 1>2.
*
*Exit:
* returns void
*
*Exceptions:
*
*******************************************************************************/
/* sort the array between lo and hi (inclusive) */
void __cdecl qsort (
void *base,
unsigned num,
unsigned width,
int (__cdecl *comp)(const void *, const void *)
)
{
char *lo, *hi; /* ends of sub-array currently sorting */
char *mid; /* points to middle of subarray */
char *loguy, *higuy; /* traveling pointers for partition step */
unsigned size; /* size of the sub-array */
char *lostk[30], *histk[30];
int stkptr; /* stack for saving sub-array to be processed */
/* Note: the number of stack entries required is no more than
1 + log2(size), so 30 is sufficient for any array */
if (num < 2 || width == 0)
return; /* nothing to do */
stkptr = 0; /* initialize stack */
lo = base;
hi = (char *)base + width * (num-1); /* initialize limits */
/* this entry point is for pseudo-recursion calling: setting
lo and hi and jumping to here is like recursion, but stkptr is
prserved, locals aren't, so we preserve stuff on the stack */
recurse:
size = (hi - lo) / width + 1; /* number of el's to sort */
/* below a certain size, it is faster to use a O(n^2) sorting method */
if (size <= CUTOFF) {
shortsort(lo, hi, width, comp);
}
else {
/* First we pick a partititioning element. The efficiency of the
algorithm demands that we find one that is approximately the
median of the values, but also that we select one fast. Using
the first one proces bad performace if the array is already
sorted, so we use the middle one, which would require a very
wierdly arranged array for worst case performance. Testing shows
that a median-of-three algorithm does not, in general, increase
performance. */
mid = lo + (size / 2) * width; /* find middle element */
swap(mid, lo, width); /* swap it to beginning of array */
/* We now wish to partition the array into three pieces, one
consisiting of elements <= partition element, one of elements
equal to the parition element, and one of element >= to it. This
is done below; comments indicate conditions established at every
step. */
loguy = lo;
higuy = hi + width;
/* Note that higuy decreases and loguy increases on every iteration,
so loop must terminate. */
for (;;) {
/* lo <= loguy < hi, lo < higuy <= hi + 1,
A[i] <= A[lo] for lo <= i <= loguy,
A[i] >= A[lo] for higuy <= i <= hi */
do {
loguy += width;
} while (loguy <= hi && comp(loguy, lo) <= 0);
/* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy,
either loguy > hi or A[loguy] > A[lo] */
do {
higuy -= width;
} while (higuy > lo && comp(higuy, lo) >= 0);
/* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi,
either higuy <= lo or A[higuy] < A[lo] */
if (higuy < loguy)
break;
/* if loguy > hi or higuy <= lo, then we would have exited, so
A[loguy] > A[lo], A[higuy] < A[lo],
loguy < hi, highy > lo */
swap(loguy, higuy, width);
/* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top
of loop is re-established */
}
/* A[i] >= A[lo] for higuy < i <= hi,
A[i] <= A[lo] for lo <= i < loguy,
higuy < loguy, lo <= higuy <= hi
implying:
A[i] >= A[lo] for loguy <= i <= hi,
A[i] <= A[lo] for lo <= i <= higuy,
A[i] = A[lo] for higuy < i < loguy */
swap(lo, higuy, width); /* put partition element in place */
/* OK, now we have the following:
A[i] >= A[higuy] for loguy <= i <= hi,
A[i] <= A[higuy] for lo <= i < higuy
A[i] = A[lo] for higuy <= i < loguy */
/* We've finished the partition, now we want to sort the subarrays
[lo, higuy-1] and [loguy, hi].
We do the smaller one first to minimize stack usage.
We only sort arrays of length 2 or more.*/
if ( higuy - 1 - lo >= hi - loguy ) {
if (lo + width < higuy) {
lostk[stkptr] = lo;
histk[stkptr] = higuy - width;
++stkptr;
} /* save big recursion for later */
if (loguy < hi) {
lo = loguy;
goto recurse; /* do small recursion */
}
}
else {
if (loguy < hi) {
lostk[stkptr] = loguy;
histk[stkptr] = hi;
++stkptr; /* save big recursion for later */
}
if (lo + width < higuy) {
hi = higuy - width;
goto recurse; /* do small recursion */
}
}
}
/* We have sorted the array, except for any pending sorts on the stack.
Check if there are any, and do them. */
--stkptr;
if (stkptr >= 0) {
lo = lostk[stkptr];
hi = histk[stkptr];
goto recurse; /* pop subarray from stack */
}
else
return; /* all subarrays done */
}
/***
*shortsort(hi, lo, width, comp) - insertion sort for sorting short arrays
*
*Purpose:
* sorts the sub-array of elements between lo and hi (inclusive)
* side effects: sorts in place
* assumes that lo < hi
*
*Entry:
* char *lo = pointer to low element to sort
* char *hi = pointer to high element to sort
* unsigned width = width in bytes of each array element
* int (*comp)() = pointer to function returning analog of strcmp for
* strings, but supplied by user for comparing the array elements.
* it accepts 2 pointers to elements and returns neg if 1<2, 0 if
* 1=2, pos if 1>2.
*
*Exit:
* returns void
*
*Exceptions:
*
*******************************************************************************/
static void __cdecl shortsort (
char *lo,
char *hi,
unsigned width,
int (__cdecl *comp)(const void *, const void *)
)
{
char *p, *max;
/* Note: in assertions below, i and j are alway inside original bound of
array to sort. */
while (hi > lo) {
/* A[i] <= A[j] for i <= j, j > hi */
max = lo;
for (p = lo+width; p <= hi; p += width) {
/* A[i] <= A[max] for lo <= i < p */
if (comp(p, max) > 0) {
max = p;
}
/* A[i] <= A[max] for lo <= i <= p */
}
/* A[i] <= A[max] for lo <= i <= hi */
swap(max, hi, width);
/* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi */
hi -= width;
/* A[i] <= A[j] for i <= j, j > hi, loop top condition established */
}
/* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j,
so array is sorted */
}
/***
*swap(a, b, width) - swap two elements
*
*Purpose:
* swaps the two array elements of size width
*
*Entry:
* char *a, *b = pointer to two elements to swap
* unsigned width = width in bytes of each array element
*
*Exit:
* returns void
*
*Exceptions:
*
*******************************************************************************/
static void __cdecl swap (
char *a,
char *b,
unsigned width
)
{
char tmp;
if ( a != b )
/* Do the swap one character at a time to avoid potential alignment
problems. */
while ( width-- ) {
tmp = *a;
*a++ = *b;
*b++ = tmp;
}
}
热心网友
时间:2023-10-22 20:25
C runtime 的源码VC也有;
我的在Microsoft Visual Studio 8\VC\crt\src
你可以写个程序,譬如函数调用strcat();,然后用右键跳到函数定义处,就行了;
热心网友
时间:2023-10-22 20:25
http://ftp.gnu.org/pub/gnu/glibc/glibc-2.5.tar.gz
http://www.gnu.org/software/libc/
参考资料:http://www.herofit.cn
热心网友
时间:2023-10-22 20:26
深入printf
/***
*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却没有。其中的原因是,在K&RC下,float值用于表达式或用作参数前,会自动转换成double类型。而ANSI C一般不会自动把float转换成double。有些程序已假定其中的float参数会被转换成double,为了保护大量这样的程序,所有printf()函数的float参数还是被自动转换成double型。因此,在K&RC或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()仍然会产生错误。
热心网友
时间:2023-10-22 20:26
你在根目录下找到stdio.h文件看看就行
那里很多的
热心网友
时间:2023-10-22 20:24
不是你表达不清,也许只是你根本不想仔细看一睛VC下面目录的源码,事实上就是有的。后附其中的qsort.c,以证明所言不虚。
VC的库是提供源码的,这东西也不值钱。
X:\Program Files\Microsoft Visual Studio\VCXX\CRT\SRC
注意有些可能本身是用汇编写的。
/***
*qsort.c - quicksort algorithm; qsort() library function for sorting arrays
*
* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* To implement the qsort() routine for sorting arrays.
*
*******************************************************************************/
#include <cruntime.h>
#include <stdlib.h>
#include <search.h>
/* prototypes for local routines */
static void __cdecl shortsort(char *lo, char *hi, unsigned width,
int (__cdecl *comp)(const void *, const void *));
static void __cdecl swap(char *p, char *q, unsigned int width);
/* this parameter defines the cutoff between using quick sort and
insertion sort for arrays; arrays with lengths shorter or equal to the
below value use insertion sort */
#define CUTOFF 8 /* testing shows that this is good value */
/***
*qsort(base, num, wid, comp) - quicksort function for sorting arrays
*
*Purpose:
* quicksort the array of elements
* side effects: sorts in place
*
*Entry:
* char *base = pointer to base of array
* unsigned num = number of elements in the array
* unsigned width = width in bytes of each array element
* int (*comp)() = pointer to function returning analog of strcmp for
* strings, but supplied by user for comparing the array elements.
* it accepts 2 pointers to elements and returns neg if 1<2, 0 if
* 1=2, pos if 1>2.
*
*Exit:
* returns void
*
*Exceptions:
*
*******************************************************************************/
/* sort the array between lo and hi (inclusive) */
void __cdecl qsort (
void *base,
unsigned num,
unsigned width,
int (__cdecl *comp)(const void *, const void *)
)
{
char *lo, *hi; /* ends of sub-array currently sorting */
char *mid; /* points to middle of subarray */
char *loguy, *higuy; /* traveling pointers for partition step */
unsigned size; /* size of the sub-array */
char *lostk[30], *histk[30];
int stkptr; /* stack for saving sub-array to be processed */
/* Note: the number of stack entries required is no more than
1 + log2(size), so 30 is sufficient for any array */
if (num < 2 || width == 0)
return; /* nothing to do */
stkptr = 0; /* initialize stack */
lo = base;
hi = (char *)base + width * (num-1); /* initialize limits */
/* this entry point is for pseudo-recursion calling: setting
lo and hi and jumping to here is like recursion, but stkptr is
prserved, locals aren't, so we preserve stuff on the stack */
recurse:
size = (hi - lo) / width + 1; /* number of el's to sort */
/* below a certain size, it is faster to use a O(n^2) sorting method */
if (size <= CUTOFF) {
shortsort(lo, hi, width, comp);
}
else {
/* First we pick a partititioning element. The efficiency of the
algorithm demands that we find one that is approximately the
median of the values, but also that we select one fast. Using
the first one proces bad performace if the array is already
sorted, so we use the middle one, which would require a very
wierdly arranged array for worst case performance. Testing shows
that a median-of-three algorithm does not, in general, increase
performance. */
mid = lo + (size / 2) * width; /* find middle element */
swap(mid, lo, width); /* swap it to beginning of array */
/* We now wish to partition the array into three pieces, one
consisiting of elements <= partition element, one of elements
equal to the parition element, and one of element >= to it. This
is done below; comments indicate conditions established at every
step. */
loguy = lo;
higuy = hi + width;
/* Note that higuy decreases and loguy increases on every iteration,
so loop must terminate. */
for (;;) {
/* lo <= loguy < hi, lo < higuy <= hi + 1,
A[i] <= A[lo] for lo <= i <= loguy,
A[i] >= A[lo] for higuy <= i <= hi */
do {
loguy += width;
} while (loguy <= hi && comp(loguy, lo) <= 0);
/* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy,
either loguy > hi or A[loguy] > A[lo] */
do {
higuy -= width;
} while (higuy > lo && comp(higuy, lo) >= 0);
/* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi,
either higuy <= lo or A[higuy] < A[lo] */
if (higuy < loguy)
break;
/* if loguy > hi or higuy <= lo, then we would have exited, so
A[loguy] > A[lo], A[higuy] < A[lo],
loguy < hi, highy > lo */
swap(loguy, higuy, width);
/* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top
of loop is re-established */
}
/* A[i] >= A[lo] for higuy < i <= hi,
A[i] <= A[lo] for lo <= i < loguy,
higuy < loguy, lo <= higuy <= hi
implying:
A[i] >= A[lo] for loguy <= i <= hi,
A[i] <= A[lo] for lo <= i <= higuy,
A[i] = A[lo] for higuy < i < loguy */
swap(lo, higuy, width); /* put partition element in place */
/* OK, now we have the following:
A[i] >= A[higuy] for loguy <= i <= hi,
A[i] <= A[higuy] for lo <= i < higuy
A[i] = A[lo] for higuy <= i < loguy */
/* We've finished the partition, now we want to sort the subarrays
[lo, higuy-1] and [loguy, hi].
We do the smaller one first to minimize stack usage.
We only sort arrays of length 2 or more.*/
if ( higuy - 1 - lo >= hi - loguy ) {
if (lo + width < higuy) {
lostk[stkptr] = lo;
histk[stkptr] = higuy - width;
++stkptr;
} /* save big recursion for later */
if (loguy < hi) {
lo = loguy;
goto recurse; /* do small recursion */
}
}
else {
if (loguy < hi) {
lostk[stkptr] = loguy;
histk[stkptr] = hi;
++stkptr; /* save big recursion for later */
}
if (lo + width < higuy) {
hi = higuy - width;
goto recurse; /* do small recursion */
}
}
}
/* We have sorted the array, except for any pending sorts on the stack.
Check if there are any, and do them. */
--stkptr;
if (stkptr >= 0) {
lo = lostk[stkptr];
hi = histk[stkptr];
goto recurse; /* pop subarray from stack */
}
else
return; /* all subarrays done */
}
/***
*shortsort(hi, lo, width, comp) - insertion sort for sorting short arrays
*
*Purpose:
* sorts the sub-array of elements between lo and hi (inclusive)
* side effects: sorts in place
* assumes that lo < hi
*
*Entry:
* char *lo = pointer to low element to sort
* char *hi = pointer to high element to sort
* unsigned width = width in bytes of each array element
* int (*comp)() = pointer to function returning analog of strcmp for
* strings, but supplied by user for comparing the array elements.
* it accepts 2 pointers to elements and returns neg if 1<2, 0 if
* 1=2, pos if 1>2.
*
*Exit:
* returns void
*
*Exceptions:
*
*******************************************************************************/
static void __cdecl shortsort (
char *lo,
char *hi,
unsigned width,
int (__cdecl *comp)(const void *, const void *)
)
{
char *p, *max;
/* Note: in assertions below, i and j are alway inside original bound of
array to sort. */
while (hi > lo) {
/* A[i] <= A[j] for i <= j, j > hi */
max = lo;
for (p = lo+width; p <= hi; p += width) {
/* A[i] <= A[max] for lo <= i < p */
if (comp(p, max) > 0) {
max = p;
}
/* A[i] <= A[max] for lo <= i <= p */
}
/* A[i] <= A[max] for lo <= i <= hi */
swap(max, hi, width);
/* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi */
hi -= width;
/* A[i] <= A[j] for i <= j, j > hi, loop top condition established */
}
/* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j,
so array is sorted */
}
/***
*swap(a, b, width) - swap two elements
*
*Purpose:
* swaps the two array elements of size width
*
*Entry:
* char *a, *b = pointer to two elements to swap
* unsigned width = width in bytes of each array element
*
*Exit:
* returns void
*
*Exceptions:
*
*******************************************************************************/
static void __cdecl swap (
char *a,
char *b,
unsigned width
)
{
char tmp;
if ( a != b )
/* Do the swap one character at a time to avoid potential alignment
problems. */
while ( width-- ) {
tmp = *a;
*a++ = *b;
*b++ = tmp;
}
}
热心网友
时间:2023-10-22 20:25
C runtime 的源码VC也有;
我的在Microsoft Visual Studio 8\VC\crt\src
你可以写个程序,譬如函数调用strcat();,然后用右键跳到函数定义处,就行了;
热心网友
时间:2023-10-22 20:25
http://ftp.gnu.org/pub/gnu/glibc/glibc-2.5.tar.gz
http://www.gnu.org/software/libc/
参考资料:http://www.herofit.cn
热心网友
时间:2023-10-22 20:26
深入printf
/***
*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却没有。其中的原因是,在K&RC下,float值用于表达式或用作参数前,会自动转换成double类型。而ANSI C一般不会自动把float转换成double。有些程序已假定其中的float参数会被转换成double,为了保护大量这样的程序,所有printf()函数的float参数还是被自动转换成double型。因此,在K&RC或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()仍然会产生错误。
热心网友
时间:2023-10-22 20:26
你在根目录下找到stdio.h文件看看就行
那里很多的