源代码来自《Linux/Unix系统编程手册》的get_num.c
/* Listing 3-6 */
/* get_num.c
Functions to process numeric command-line arguments.
*/
#include
#include
#include
#include
#include
#include "get_num.h"
/* Print a diagnostic message that contains a function name ('fname'),
the value of a command-line argument ('arg'), the name of that
command-line argument ('name'), and a diagnostic error message ('msg'). */
static void
gnFail(const char *fname, const char *msg, const char *arg, const char *name)
{
fprintf(stderr, "%s error", fname);
if (name != NULL)
fprintf(stderr, " (in %s)", name);
fprintf(stderr, ": %s\n", msg);
if (arg != NULL && *arg != '\0')
fprintf(stderr, " offending text: %s\n", arg);
exit(EXIT_FAILURE);
}
/* Convert a numeric command-line argument ('arg') into a long integer,
returned as the function result. 'flags' is a bit mask of flags controlling
how the conversion is done and what diagnostic checks are performed on the
numeric result; see get_num.h for details.
'fname' is the name of our caller, and 'name' is the name associated with
the command-line argument 'arg'. 'fname' and 'name' are used to print a
diagnostic message in case an error is detected when processing 'arg'. */
static long
getNum(const char *fname, const char *arg, int flags, const char *name)
{
long res;
char *endptr;
int base;
if (arg == NULL || *arg == '\0')
gnFail(fname, "null or empty string", arg, name);
base = (flags & GN_ANY_BASE) ? 0 : (flags & GN_BASE_8) ? 8
: (flags & GN_BASE_16) ? 16
: 10;
errno = 0;
res = strtol(arg, &endptr, base);
if (errno != 0)
gnFail(fname, "strtol() failed", arg, name);
if (*endptr != '\0')
gnFail(fname, "nonnumeric characters", arg, name);
if ((flags & GN_NONNEG) && res < 0)
gnFail(fname, "negative value not allowed", arg, name);
if ((flags & GN_GT_0) && res <= 0)
gnFail(fname, "value must be > 0", arg, name);
return res;
}
/* Convert a numeric command-line argument string to a long integer. See the
comments for getNum() for a description of the arguments to this function. */
long getLong(const char *arg, int flags, const char *name)
{
return getNum("getLong", arg, flags, name);
}
/* Convert a numeric command-line argument string to an integer. See the
comments for getNum() for a description of the arguments to this function. */
int getInt(const char *arg, int flags, const char *name)
{
long res;
res = getNum("getInt", arg, flags, name);
if (res > INT_MAX || res < INT_MIN)
gnFail("getInt", "integer out of range", arg, name);
return res;
}
NULL的定义如下:
#ifndef __cplusplus
#define NULL ((void *)0)
#else /* C++ */
#define NULL 0
#endif /* C++ */
#endif /* G++ */
#endif /* NULL not defined and or need NULL. */
NULL在数值上为0,在C语言中表示空指针,类型为void*,在C++中表示0;
'0’是字符0,ASCII码值即数值上为48;
0在数值上为0;
'\0’是空字符(null character),数值上为0,C语言用于标记字符串的结尾;
"\0"为字符串,包含两个空字符。
flags & GN_ANY_BASE利用位操作实现掩码操作,在get_num.h文件中定义如下:
#define GN_NONNEG 01 /* Value must be >= 0 */
#define GN_GT_0 02 /* Value must be > 0 */
#define GN_ANY_BASE 0100 /* Can use any base - like strtol(3) */
#define GN_BASE_8 0200 /* Value is expressed in octal */
#define GN_BASE_16 0400 /* Value is expressed in hexadecimal */
0开头表示8进制,0100、0200、0400转换为2进制显示后,三个数分别为:
0000 0100 0000
0000 1000 0000
0001 0000 0000
三者在bit位上没有重叠,仅有1位为1,通过按位&操作可以检查flags的某个bit是否为1,如果该bit为1,则flags & GN_ANY_BASE的结果为1,如果该bit不为1,则flags & GN_ANY_BASE的结果为0。
代码中使用了嵌套的条件运算符:
base = (flags & GN_ANY_BASE) ? 0 : (flags & GN_BASE_8) ? 8
: (flags & GN_BASE_16) ? 16
: 10;
条件运算符?:是C语言中唯一的三目运算符。条件运算符遵循从右至左的结合律,因此上述代码等同于:
base = (flags & GN_ANY_BASE) ? 0 : ((flags & GN_BASE_8) ? 8 : ((flags & GN_BASE_16) ? 16 : 10));
运算顺序与结合顺序不是同一个概念,条件运算符先计算flags & GN_ANY_BASE的结果是否为0,再根据结果进入相应的分支。
函数功能,将字符串转换为长整型数。
函数原型:
long int strtol (const char* str, char** endptr, int base);
当 base 的值为 0 时,默认为10进制转换,但如果遇到 ‘0x’ / ‘0X’ 前置字符则会使用 16 进制转换,遇到 ‘0’ 前置字符则会使用8进制转换。
当endptr为NULL,则表示该参数无效,或不使用该参数,若不为NULL,会返回不符合base的字符的指针,举例来说,base为10,则str字符串为"1223214ABC"中,从’A’开始不符合base条件,则(*endptr)指向’A’的地址。
【1】https://zhuanlan.zhihu.com/p/79210633
【2】https://www.cnblogs.com/xiehongfeng100/p/4010802.html
【3】https://www.cnblogs.com/grandyang/p/4966132.html