一、下载地址
如果你不想知道步骤,只想下载源码,这是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 <stdarg.h>. 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语言源码的话,建议你直接放弃~