怎样找到C语言本身的源码(比如stdio),对学习C语言有帮助吗?

怎样找到C语言本身的源码(比如stdio),对学习C语言有帮助吗?

一、下载地址

如果你不想知道步骤,只想下载源码,这是2021-08-01发布的glibc-3.24的下载地址:

https://ftp.gnu.org/gnu/libc/glibc-2.34.tar.gz

二、怎么知道从哪里下载

stackoverflow上有一个问题:Where can I find the source code for all the C standard libraries?,其中有一个答案提到了glibc官网。

在glibc官网页面点这里:

在详情页面搜索download

来到了gnu的ftp服务器,然后按版本号或年份去找对应的版本,比如2011年的在这里,点击就可以下载了:

三、C本身的源码对学习C语言有帮助吗

3.1 我的答案是:帮助不大

在上面的stackoverflow的答案中有这么一句话,意思是:所有人都建议你不要去看C语言的具体实现。(前人走弯路的经验啊) 我没信这个邪,偏要去下载。然后我看到:

3.2 printf源码

printf方法定义在glibc-2.34/stdio-common/printf.c文件中,代码如下:

int

__printf (const char *format, ...)

{

va_list arg;

int done;

va_start (arg, format);

done = __vfprintf_internal (stdout, format, arg, 0);

va_end (arg);

return done;

}

里面调用了__vfprintf_internal方法

3.3 __vfprintf_internal的源码

__vfprintf_internal方法定义在glibc-2.34/stdio-common/vfprintf-internal.c文件中,__vfprintf_internal是vfprintf方法的别名(# define vfprintf __vfprintf_internal),vfprintf方法的代码如下(我已经看不懂这段300多行的代码了):

int

vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)

{

/* The character used as thousands separator. */

THOUSANDS_SEP_T thousands_sep = 0;

/* The string describing the size of groups of digits. */

const char *grouping;

/* Place to accumulate the result. */

int done;

/* Current character in format string. */

const UCHAR_T *f;

/* End of leading constant string. */

const UCHAR_T *lead_str_end;

/* Points to next format specifier. */

const UCHAR_T *end_of_spec;

/* Buffer intermediate results. */

CHAR_T work_buffer[WORK_BUFFER_SIZE];

CHAR_T *workend;

/* We have to save the original argument pointer. */

va_list ap_save;

/* Count number of specifiers we already processed. */

int nspecs_done;

/* For the %m format we may need the current `errno' value. */

int save_errno = errno;

/* 1 if format is in read-only memory, -1 if it is in writable memory,

0 if unknown. */

int readonly_format = 0;

/* Orient the stream. */

#ifdef ORIENT

ORIENT;

#endif

/* Sanity check of arguments. */

ARGCHECK (s, format);

#ifdef ORIENT

/* Check for correct orientation. */

if (_IO_vtable_offset (s) == 0

&& _IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1)

!= (sizeof (CHAR_T) == 1 ? -1 : 1))

/* The stream is already oriented otherwise. */

return EOF;

#endif

if (UNBUFFERED_P (s))

/* Use a helper function which will allocate a local temporary buffer

for the stream and then call us again. */

return buffered_vfprintf (s, format, ap, mode_flags);

/* Initialize local variables. */

done = 0;

grouping = (const char *) -1;

#ifdef __va_copy

/* This macro will be available soon in gcc's . We need it

since on some systems `va_list' is not an integral type. */

__va_copy (ap_save, ap);

#else

ap_save = ap;

#endif

nspecs_done = 0;

#ifdef COMPILE_WPRINTF

/* Find the first format specifier. */

f = lead_str_end = __find_specwc ((const UCHAR_T *) format);

#else

/* Find the first format specifier. */

f = lead_str_end = __find_specmb ((const UCHAR_T *) format);

#endif

/* Lock stream. */

_IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);

_IO_flockfile (s);

/* Write the literal text before the first format. */

outstring ((const UCHAR_T *) format,

lead_str_end - (const UCHAR_T *) format);

/* If we only have to print a simple string, return now. */

if (*f == L_('\0'))

goto all_done;

/* Use the slow path in case any printf handler is registered. */

if (__glibc_unlikely (__printf_function_table != NULL

|| __printf_modifier_table != NULL

|| __printf_va_arg_table != NULL))

goto do_positional;

/* Process whole format string. */

do

{

STEP0_3_TABLE;

STEP4_TABLE;

union printf_arg *args_value; /* This is not used here but ... */

int is_negative; /* Flag for negative number. */

union

{

unsigned long long int longlong;

unsigned long int word;

} number;

int base;

union printf_arg the_arg;

CHAR_T *string; /* Pointer to argument string. */

int alt = 0; /* Alternate format. */

int space = 0; /* Use space prefix if no sign is needed. */

int left = 0; /* Left-justify output. */

int showsign = 0; /* Always begin with plus or minus sign. */

int group = 0; /* Print numbers according grouping rules. */

int is_long_double = 0; /* Argument is long double/ long long int. */

int is_short = 0; /* Argument is short int. */

int is_long = 0; /* Argument is long int. */

int is_char = 0; /* Argument is promoted (unsigned) char. */

int width = 0; /* Width of output; 0 means none specified. */

int prec = -1; /* Precision of output; -1 means none specified. */

/* This flag is set by the 'I' modifier and selects the use of the

`outdigits' as determined by the current locale. */

int use_outdigits = 0;

UCHAR_T pad = L_(' ');/* Padding character. */

CHAR_T spec;

workend = work_buffer + WORK_BUFFER_SIZE;

/* Get current character in format string. */

JUMP (*++f, step0_jumps);

/* ' ' flag. */

LABEL (flag_space):

space = 1;

JUMP (*++f, step0_jumps);

/* '+' flag. */

LABEL (flag_plus):

showsign = 1;

JUMP (*++f, step0_jumps);

/* The '-' flag. */

LABEL (flag_minus):

left = 1;

pad = L_(' ');

JUMP (*++f, step0_jumps);

/* The '#' flag. */

LABEL (flag_hash):

alt = 1;

JUMP (*++f, step0_jumps);

/* The '0' flag. */

LABEL (flag_zero):

if (!left)

pad = L_('0');

JUMP (*++f, step0_jumps);

/* The '\'' flag. */

LABEL (flag_quote):

group = 1;

if (grouping == (const char *) -1)

{

#ifdef COMPILE_WPRINTF

thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,

_NL_NUMERIC_THOUSANDS_SEP_WC);

#else

thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);

#endif

grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);

if (*grouping == '\0' || *grouping == CHAR_MAX

#ifdef COMPILE_WPRINTF

|| thousands_sep == L'\0'

#else

|| *thousands_sep == '\0'

#endif

)

grouping = NULL;

}

JUMP (*++f, step0_jumps);

LABEL (flag_i18n):

use_outdigits = 1;

JUMP (*++f, step0_jumps);

/* Get width from argument. */

LABEL (width_asterics):

{

const UCHAR_T *tmp; /* Temporary value. */

tmp = ++f;

if (ISDIGIT (*tmp))

{

int pos = read_int (&tmp);

if (pos == -1)

{

__set_errno (EOVERFLOW);

done = -1;

goto all_done;

}

if (pos && *tmp == L_('$'))

/* The width comes from a positional parameter. */

goto do_positional;

}

width = va_arg (ap, int);

/* Negative width means left justified. */

if (width < 0)

{

width = -width;

pad = L_(' ');

left = 1;

}

}

JUMP (*f, step1_jumps);

/* Given width in format string. */

LABEL (width):

width = read_int (&f);

if (__glibc_unlikely (width == -1))

{

__set_errno (EOVERFLOW);

done = -1;

goto all_done;

}

if (*f == L_('$'))

/* Oh, oh. The argument comes from a positional parameter. */

goto do_positional;

JUMP (*f, step1_jumps);

LABEL (precision):

++f;

if (*f == L_('*'))

{

const UCHAR_T *tmp; /* Temporary value. */

tmp = ++f;

if (ISDIGIT (*tmp))

{

int pos = read_int (&tmp);

if (pos == -1)

{

__set_errno (EOVERFLOW);

done = -1;

goto all_done;

}

if (pos && *tmp == L_('$'))

/* The precision comes from a positional parameter. */

goto do_positional;

}

prec = va_arg (ap, int);

/* If the precision is negative the precision is omitted. */

if (prec < 0)

prec = -1;

}

else if (ISDIGIT (*f))

{

prec = read_int (&f);

/* The precision was specified in this case as an extremely

large positive value. */

if (prec == -1)

{

__set_errno (EOVERFLOW);

done = -1;

goto all_done;

}

}

else

prec = 0;

JUMP (*f, step2_jumps);

/* Process 'h' modifier. There might another 'h' following. */

LABEL (mod_half):

is_short = 1;

JUMP (*++f, step3a_jumps);

/* Process 'hh' modifier. */

LABEL (mod_halfhalf):

is_short = 0;

is_char = 1;

JUMP (*++f, step4_jumps);

/* Process 'l' modifier. There might another 'l' following. */

LABEL (mod_long):

is_long = 1;

JUMP (*++f, step3b_jumps);

/* Process 'L', 'q', or 'll' modifier. No other modifier is

allowed to follow. */

LABEL (mod_longlong):

is_long_double = 1;

is_long = 1;

JUMP (*++f, step4_jumps);

LABEL (mod_size_t):

is_long_double = sizeof (size_t) > sizeof (unsigned long int);

is_long = sizeof (size_t) > sizeof (unsigned int);

JUMP (*++f, step4_jumps);

LABEL (mod_ptrdiff_t):

is_long_double = sizeof (ptrdiff_t) > sizeof (unsigned long int);

is_long = sizeof (ptrdiff_t) > sizeof (unsigned int);

JUMP (*++f, step4_jumps);

LABEL (mod_intmax_t):

is_long_double = sizeof (intmax_t) > sizeof (unsigned long int);

is_long = sizeof (intmax_t) > sizeof (unsigned int);

JUMP (*++f, step4_jumps);

/* Process current format. */

while (1)

{

process_arg (((struct printf_spec *) NULL));

process_string_arg (((struct printf_spec *) NULL));

LABEL (form_unknown):

if (spec == L_('\0'))

{

/* The format string ended before the specifier is complete. */

__set_errno (EINVAL);

done = -1;

goto all_done;

}

/* If we are in the fast loop force entering the complicated

one. */

goto do_positional;

}

/* The format is correctly handled. */

++nspecs_done;

/* Look for next format specifier. */

#ifdef COMPILE_WPRINTF

f = __find_specwc ((end_of_spec = ++f));

#else

f = __find_specmb ((end_of_spec = ++f));

#endif

/* Write the following constant string. */

outstring (end_of_spec, f - end_of_spec);

}

while (*f != L_('\0'));

/* Unlock stream and return. */

goto all_done;

/* Hand off processing for positional parameters. */

do_positional:

done = printf_positional (s, format, readonly_format, ap, &ap_save,

done, nspecs_done, lead_str_end, work_buffer,

save_errno, grouping, thousands_sep, mode_flags);

all_done:

/* Unlock the stream. */

_IO_funlockfile (s);

_IO_cleanup_region_end (0);

return done;

}

3.4 还有很多汇编文件

在查东西的时候还发现源码里面有大量的汇编文件,比如glibc-2.34/sysdeps/x86_64/multiarch目录下的文件: 即C文件里面又调用了汇编文件里面的方法。 我已经了解一些粗浅的C语言和汇编相关的知识了,但是看C语言源码中的C文件和汇编文件基本上还是看不懂,所以如果你不是钻研C语言源码的话,建议你直接放弃~

风雨相关

瘦瘦包的正确用法 瘦瘦包应该怎么使用
365bet技巧

瘦瘦包的正确用法 瘦瘦包应该怎么使用

🌀 07-09 💧 阅读 1853
微克到毫克转换计算器
365bet足球比分

微克到毫克转换计算器

🌀 07-22 💧 阅读 3699
A. 市场上有哪些主要的银行贷款类型?
爱享365

A. 市场上有哪些主要的银行贷款类型?

🌀 08-10 💧 阅读 9768