Last Updated: 2024-03-27 07:36:29 Wednesday
-- TOC --
学习C语言标准库,寻找乐趣和裨益!~~~
// Upon successful return, these functions return the number of
// characters printed (excluding the null byte used to end output to strings).
// 如果输出字符串中间含有null,字符串到此就结束!不要出现这种情况...
int printf(const char *restrict format, ...);
int fprintf(FILE *restrict stream,
const char *restrict format, ...);
int dprintf(int fd,
const char *restrict format, ...);
// s must be big enough to hold the result (including the last null byte).
// 返回的长度不包括最后的null字节。
int sprintf(char *restrict str,
const char *restrict format, ...);
// write at most size bytes (including the terminating null byte) to str.
// 此接口返回值表示str空间无限大时的写入长度,如果返回值大于size-1,表示truncated。
int snprintf(char *restrict str, size_t size,
const char *restrict format, ...);
// sprintf和snprintf都是自动在最后写入null,因为这是string。
在C语言中转换或拼接string,可以使用sprintf或snprintf接口。但是要注意一个Undefined Behavior场景:输出地址和输入地址如果存在overlap的时候。比如:
// Don't Do This..!!! Memory Overlap...
sprintf(buf, "%s some further text", buf);
// mode: r, r+, w, w+, a, a+.
// The mode string can also include the letter 'b' either as a last
// character or as a character between the characters in any of the
// two-character strings described above.
FILE *fopen(const char *restrict pathname, const char *restrict mode);
// The function fread() reads nmemb items of data, each size bytes long,
// from the stream pointed to by stream, storing them at the location
// given by ptr.
size_t fread(void *restrict ptr, size_t size, size_t nmemb,
FILE *restrict stream);
// The function fwrite() writes nmemb items of data, each size bytes long,
// to the stream pointed to by stream, obtaining them from the location
// given by ptr.
size_t fwrite(const void *restrict ptr, size_t size, size_t nmemb,
FILE *restrict stream);
// closed after flush, but only flush user space data provided by C lib.
int fclose(FILE *stream);
// Only flush user space data provided by C lib.
// If the stream argument is NULL,
// fflush() flushes all open output streams.
int fflush(FILE *stream);
// Set the file position indicator.
// whence: SEEK_SET, SEEK_CUR, SEEK_END
// Offset would be negative value.
int fseek(FILE *stream, long offset, int whence);
// Tp obtains the current value of the file position indicator for
// the stream pointed to by stream.
long ftell(FILE *stream);
// The tmpfile() function opens a unique temporary file
// in binary read/write (w+b) mode.
// The file will be automatically deleted when it is closed or
// the program terminates.
// 这是个非常nice的功能接口。但在Windows下使用这个接口
// 可能会存在权限的问题,据说默认是在C盘根目录创建文件。
FILE *tmpfile(void);
FILE *fn = fopen("test.txt", "r");
fseek(fn, 0L, SEEK_END);
long file_size = ftell(fn);
fclose(fn);
// fputc() writes the character c, cast to an unsigned char, to stream.
int fputc(int c, FILE *stream);
// putc() is equivalent to fputc() except that it may be implemented as a macro,
// which evaluates stream more than once.
int putc(int c, FILE *stream);
// putchar(c) is equivalent to putc(c, stdout).
int putchar(int c);
// fputs() writes the string s to stream, without its terminating null byte ('\0').
int fputs(const char *restrict s, FILE *restrict stream);
// puts() writes the string s and a trailing newline to stdout.
// puts固定向stdout输出,自动添加newline,倒是提供了一点便利性。
int puts(const char *s);
// 当errno被设置后,用perror接口,打印出系统定义的errno对应的字符串。
// 入参是一个额外的输出字符串,用户自定义,先打印这个。
void perror(const char *s);
// 我常用的Macro,当出错时,提示文件名和行号,方便定位。
#define _PEXIT \
do {\
char ebuf[64] = {0};\
sprintf(ebuf, "%s: %d", __FILE__, __LINE__);\
perror(ebuf);\
exit(errno);\
}while(0)
对比strerror接口,它需要以errno作为输入。而perror直接将对应的string打印出来。
#include <stdlib.h>
// 将输入字符串的初始部分转换成整形数据或浮点数。
// 不建议再使用的下面4个接口,原因:
// 1. 发生错误返回0,但0可能是正常值,并且不设置errno
// 2. 没有underflow和overflow的检查
// 3. 只支持10进制
int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
double atof(const char *nptr);
// 下面是建议使用的转换接口!
// 1. 转换nptr指向字符串的初始部分,可以有space,可以有+-符号
// 2. 如果**endptr不为NULL,函数执行结束后,*endptr指向第1个非数字字符
// 3. 可在2到36之间设置进制,0是特殊值
// 4. 出错时会设置errno,但需要用户自己在调用前将errno清零,
// 因为接口可以合法返回0,调用之后,由用户自己判断errno是否为非0。
// 5. manpage有使用case,这组接口还挺复杂的
long strtol(const char *restrict nptr,
char **restrict endptr, int base);
long long strtoll(const char *restrict nptr,
char **restrict endptr, int base);
unsigned long strtoul(const char *restrict nptr,
char **restrict endptr, int base);
unsigned long long strtoull(const char *restrict nptr,
char **restrict endptr, int base);
float strtof(const char *restrict nptr, char **restrict endptr);
double strtod(const char *restrict nptr, char **restrict endptr);
long double strtold(const char *restrict nptr, char **restrict endptr);
- 64位的Linux下,long和long long,都是8字节。在64位的Windows平台下,前者是4字节,后者是8字节。
- 数字转字符串,使用sprintf接口。
- 关于这一组接口更多使用细节,参考LeetCode第8题,字符串转整型数,后面单独的那个C语言版本。
- strtof和strtod可以正确解析inf和nan字符串。
C++在
<string>
中也提供了一组功能相似的接口,名为sto*
,具体参考:https://en.cppreference.com/w/cpp/string/basic_string/stol,包含一个stoi
接口。
// base指向内存块的起始位置,
// nmemb表示元素的个数,
// size表示每个元素的大小,
// compar是一个返回int的函数指针,返回值有负,零,正三种情况。
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void*, const void*));
// key: 要查找对象的值
// base: 序列的起始地址,序列按升序排列!
// nmemb: 序列中元素个数
// size: 每个元素的大小
// compar: 在key与元素比较时调用,返回值有负,零,正三种情况。
void *bsearch(const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void*, const void*));
// 返回NULL表示没有找到,否则返回指向元素的指针。
qsort和bsearch可共用一个compar接口
qsort和bsearch对compar接口的要求是完全一样的,因此可共用,示例如下:
#include <stdio.h>
#include <stdlib.h>
static int comp(const void *a, const void *b){
int aa = *(int*)a;
int bb = *(int*)b;
return aa<bb ? -1 : aa>bb ? 1 : 0;
}
int main(){
int data[] = {123,-234,345,-456,-2,0x80000001,2};
int size = sizeof(data) / sizeof(int);
qsort(data, size, sizeof(int), comp);
printf("* sorted:\n");
for(int i=0; i<size; ++i)
printf("%d\n", data[i]);
int key = 2;
int *p = bsearch(&key, data, size, sizeof(int), comp);
if(!p)
printf("* the value %d is not in the array!\n", key);
else
printf("* found! %d, index: %ld\n", *p, p-data);
return 0;
}
运行输出:
* sorted:
-2147483647
-456
-234
-2
2
123
345
* found! 2, index: 4
// free(0)是合法的,内部有检查!
void free(void *ptr);
// The memory is not initialized. If size is 0, then malloc()
// returns either NULL, or a unique pointer value that can later be
// successfully passed to free(). 得到的内存未初始化。
void *malloc(size_t size);
// The memory is set to zero. If nmemb or size is 0, then calloc()
// returns either NULL, or a unique pointer value that can later be
// successfully passed to free(). 得到的内存已被初始化为0。
void *calloc(size_t nmemb, size_t size);
// To change the size of the memory block pointed to by ptr to size bytes.
// The contents will be unchanged in the range from the start of the region
// up to the minimum of the old and new sizes. 伸缩内存大小。
// 如果size比原来的大,新加的部分内存不会被初始化。
// 如果ptr==NULL,等同于调用ptr=malloc(size)。
// 需要避免size==0而ptr!=NULL的情况,这是UB。
// Unless ptr is NULL, it must have been returned by an earlier
// call to malloc(), calloc(), or realloc().
// If the area pointed to was moved, a free(ptr) is done.
// 我理解此接口有可能改变ptr的位置,而原来的位置会自动free。
void *realloc(void *ptr, size_t size);
在C语言中使用这几个接口,不需要强转返回,即不需要强行将void*转换成某种其它类型的指针。但C++不允许这么干,C++的type system比C要严格!
// 返回一个随机数,范围是 [0,RAND_MAX],测试打印RAND_MAX的值为2147483647。
int rand(void);
// The srand() function sets its argument as the seed for a new
// sequence of pseudo-random integers to be returned by rand().
// These sequences are repeatable by calling srand() with the
// same seed value. If no seed value is provided, the rand()
// function is automatically seeded with a value of 1.
void srand(unsigned int seed);
exit是正常退出,接口可以带一个程序的返回码。
// 设置返回码,结束进程
noreturn void exit(int status);
abort是异常退出,接口不带返回码,执行到abort时,会产生coredump。assert使用abort结束进程。
noreturn void abort(void);
// 执行一个shell command,或者可用于探测系统shell是否存在。
// fork and execl("/bin/sh", "sh", "-c", command, (char *) NULL)
// 阻塞执行command。
int system(const char *command);
stdint.h
是C99标准定义的一个头文件,它定义了各种fixed-sized integer,个人认为应该尽量使用这些定义。
各种确定size的int
,signed或unsigned:
#include <stdio.h>
#include <stdint.h>
int main(void) {
int8_t i8=1;
int16_t i16=2;
int32_t i32=3;
int64_t i64=4;
printf("%d %d %d %ld\n", i8,i16,i32,i64);
uint8_t ui8=1;
uint16_t ui16=2;
uint32_t ui32=3;
uint64_t ui64=4;
printf("%u %u %u %lu\n", i8,i16,i32,i64);
return 0;
}
32位
,就是Windows下常见的DWORD
类型。long
,在32位系统下是32位,在64位系统下就是64位的。.long
是32位的。long long
总是64位。16位
。不排除未来还有更高端的芯片出现,int的长度是否会变呢?既然不同的处理器平台有各种区别,那么使用确定size的int,可以避免很多麻烦和bug。
stdint.h
中还有这样一类我们平常不太会用得到的类型,它们的名称型为[u]int_leastN_t
或[u]int_fastN_t
,它们不是确定size的int,但是从名称上理解,它们提供了一个确定最小size的int
。
int_leastN_t is required in all C99 implementation for values
of N of 8, 16, 32, and 64.
This is the "minimum-width integer types".
int_fastN_t is required in all C99 implementation for values
of N of 8, 16, 32, and 64.
This is the "fastest minimum-width integer types".
leastN表示最少有N位的int,而fastN也表示最少有N位的int,但它多了一个约束,fast,要最快的。
如何理解fastN_t?
For example, on a machine with 8 bit bytes and 32 bit fast
registers, int8_t and int_least8_t are aliased to signed
char but int_fast8_t is aliased to int32_t. Whereas,
if the implementation chose to define them, int_least24_t
and int_fast24_t would both be aliased to int32_t, with
int24_t left undefined.
int8_t和int_least8_t对应int8_t;
int_fast8_t对应int32_t;
CPU将一个变量从内存load进register,修改,再write back to memory。不同size的变量,编译之后对应的汇编语句的数量可能都不同,一般32位的CPU,处理int32_t是最快的。定义int_fastN_t,就是这个道理。
下面是/usr/include/stdint.h
中的一组定义:
/* Fast types. */
/* Signed. */
typedef signed char int_fast8_t;
#if __WORDSIZE == 64
typedef long int int_fast16_t;
typedef long int int_fast32_t;
typedef long int int_fast64_t;
#else
typedef int int_fast16_t;
typedef int int_fast32_t;
__extension__
typedef long long int int_fast64_t;
#endif
/* Unsigned. */
typedef unsigned char uint_fast8_t;
#if __WORDSIZE == 64
typedef unsigned long int uint_fast16_t;
typedef unsigned long int uint_fast32_t;
typedef unsigned long int uint_fast64_t;
#else
typedef unsigned int uint_fast16_t;
typedef unsigned int uint_fast32_t;
__extension__
typedef unsigned long long int uint_fast64_t;
#endif
stdint.h
中,还定义了各种size的int的极限值,方便程序代码直接使用,增加代码的可读性。
下面的内容,来自/usr/include/stdint.h
文件:
# if __WORDSIZE == 64
# define __INT64_C(c) c ## L
# define __UINT64_C(c) c ## UL
# else
# define __INT64_C(c) c ## LL
# define __UINT64_C(c) c ## ULL
# endif
/* Limits of integral types. */
/* Minimum of signed integral types. */
# define INT8_MIN (-128)
# define INT16_MIN (-32767-1)
# define INT32_MIN (-2147483647-1)
# define INT64_MIN (-__INT64_C(9223372036854775807)-1)
/* Maximum of signed integral types. */
# define INT8_MAX (127)
# define INT16_MAX (32767)
# define INT32_MAX (2147483647)
# define INT64_MAX (__INT64_C(9223372036854775807))
/* Maximum of unsigned integral types. */
# define UINT8_MAX (255)
# define UINT16_MAX (65535)
# define UINT32_MAX (4294967295U)
# define UINT64_MAX (__UINT64_C(18446744073709551615))
/* Minimum of signed integral types having a minimum size. */
# define INT_LEAST8_MIN (-128)
# define INT_LEAST16_MIN (-32767-1)
# define INT_LEAST32_MIN (-2147483647-1)
# define INT_LEAST64_MIN (-__INT64_C(9223372036854775807)-1)
/* Maximum of signed integral types having a minimum size. */
# define INT_LEAST8_MAX (127)
# define INT_LEAST16_MAX (32767)
# define INT_LEAST32_MAX (2147483647)
# define INT_LEAST64_MAX (__INT64_C(9223372036854775807))
/* Maximum of unsigned integral types having a minimum size. */
# define UINT_LEAST8_MAX (255)
# define UINT_LEAST16_MAX (65535)
# define UINT_LEAST32_MAX (4294967295U)
# define UINT_LEAST64_MAX (__UINT64_C(18446744073709551615))
/* Minimum of fast signed integral types having a minimum size. */
# define INT_FAST8_MIN (-128)
# if __WORDSIZE == 64
# define INT_FAST16_MIN (-9223372036854775807L-1)
# define INT_FAST32_MIN (-9223372036854775807L-1)
# else
# define INT_FAST16_MIN (-2147483647-1)
# define INT_FAST32_MIN (-2147483647-1)
# endif
# define INT_FAST64_MIN (-__INT64_C(9223372036854775807)-1)
/* Maximum of fast signed integral types having a minimum size. */
# define INT_FAST8_MAX (127)
# if __WORDSIZE == 64
# define INT_FAST16_MAX (9223372036854775807L)
# define INT_FAST32_MAX (9223372036854775807L)
# else
# define INT_FAST16_MAX (2147483647)
# define INT_FAST32_MAX (2147483647)
# endif
# define INT_FAST64_MAX (__INT64_C(9223372036854775807))
/* Maximum of fast unsigned integral types having a minimum size. */
# define UINT_FAST8_MAX (255)
# if __WORDSIZE == 64
# define UINT_FAST16_MAX (18446744073709551615UL)
# define UINT_FAST32_MAX (18446744073709551615UL)
# else
# define UINT_FAST16_MAX (4294967295U)
# define UINT_FAST32_MAX (4294967295U)
# endif
# define UINT_FAST64_MAX (__UINT64_C(18446744073709551615))
stdint.h
中的主要内容,就是上面这些了,还有一些其它内容,有兴趣的同学,请自行阅读源码。
头文件limits.h提供了各种size的int的最大最小值。stdint.h中也有最大最小值定义,但他们都是针对stdint.h中定义的类型。下面是经过整理的limits.h内容:
/* Number of bits in a `char'. */
# define CHAR_BIT 8
/* Minimum and maximum values a `signed char' can hold. */
# define SCHAR_MIN (-128)
# define SCHAR_MAX 127
/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
# define UCHAR_MAX 255
/* Minimum and maximum values a `signed short int' can hold. */
# define SHRT_MIN (-32768)
# define SHRT_MAX 32767
/* Maximum value an `unsigned short int' can hold. (Minimum is 0.) */
# define USHRT_MAX 65535
/* Minimum and maximum values a `signed int' can hold. */
# define INT_MIN (-INT_MAX - 1)
# define INT_MAX 2147483647
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
# define UINT_MAX 4294967295U
/* Minimum and maximum values a `signed long int' can hold. */
# if __WORDSIZE == 64
# define LONG_MAX 9223372036854775807L
# else
# define LONG_MAX 2147483647L
# endif
# define LONG_MIN (-LONG_MAX - 1L)
/* Maximum value an `unsigned long int' can hold. (Minimum is 0.) */
# if __WORDSIZE == 64
# define ULONG_MAX 18446744073709551615UL
# else
# define ULONG_MAX 4294967295UL
# endif
/* Minimum and maximum values a `signed long long int' can hold. */
# define LLONG_MAX 9223372036854775807LL
# define LLONG_MIN (-LLONG_MAX - 1LL)
/* Maximum value an `unsigned long long int' can hold. (Minimum is 0.) */
# define ULLONG_MAX 18446744073709551615ULL
/* integer width */
# define CHAR_WIDTH 8
# define SCHAR_WIDTH 8
# define UCHAR_WIDTH 8
# define SHRT_WIDTH 16
# define USHRT_WIDTH 16
# define INT_WIDTH 32
# define UINT_WIDTH 32
# define LLONG_WIDTH 64
# define ULLONG_WIDTH 64
这个头文件中定义了很多printf接口所用到的类型specifier。
为了写出更好更安全的可移植代码,
<stdint.h>
,<limits.h>
和<inttypes.h>
这三个头文件非常重要!我们要尽量使用这三个头文件提供的各种定义,避免直接在代码中使用直接使用int,long...
等原始类型。
inttypes.h文件内容如下:
/* Copyright (C) 1997-2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/*
* ISO C99: 7.8 Format conversion of integer types <inttypes.h>
*/
#ifndef _INTTYPES_H
#define _INTTYPES_H 1
#include <features.h>
/* Get the type definitions. */
#include <stdint.h>
/* Get a definition for wchar_t. But we must not define wchar_t itself. */
#ifndef ____gwchar_t_defined
# ifdef __cplusplus
# define __gwchar_t wchar_t
# elif defined __WCHAR_TYPE__
typedef __WCHAR_TYPE__ __gwchar_t;
# else
# define __need_wchar_t
# include <stddef.h>
typedef wchar_t __gwchar_t;
# endif
# define ____gwchar_t_defined 1
#endif
# if __WORDSIZE == 64
# define __PRI64_PREFIX "l"
# define __PRIPTR_PREFIX "l"
# else
# define __PRI64_PREFIX "ll"
# define __PRIPTR_PREFIX
# endif
/* Macros for printing format specifiers. */
/* Decimal notation. */
# define PRId8 "d"
# define PRId16 "d"
# define PRId32 "d"
# define PRId64 __PRI64_PREFIX "d"
# define PRIdLEAST8 "d"
# define PRIdLEAST16 "d"
# define PRIdLEAST32 "d"
# define PRIdLEAST64 __PRI64_PREFIX "d"
# define PRIdFAST8 "d"
# define PRIdFAST16 __PRIPTR_PREFIX "d"
# define PRIdFAST32 __PRIPTR_PREFIX "d"
# define PRIdFAST64 __PRI64_PREFIX "d"
# define PRIi8 "i"
# define PRIi16 "i"
# define PRIi32 "i"
# define PRIi64 __PRI64_PREFIX "i"
# define PRIiLEAST8 "i"
# define PRIiLEAST16 "i"
# define PRIiLEAST32 "i"
# define PRIiLEAST64 __PRI64_PREFIX "i"
# define PRIiFAST8 "i"
# define PRIiFAST16 __PRIPTR_PREFIX "i"
# define PRIiFAST32 __PRIPTR_PREFIX "i"
# define PRIiFAST64 __PRI64_PREFIX "i"
/* Octal notation. */
# define PRIo8 "o"
# define PRIo16 "o"
# define PRIo32 "o"
# define PRIo64 __PRI64_PREFIX "o"
# define PRIoLEAST8 "o"
# define PRIoLEAST16 "o"
# define PRIoLEAST32 "o"
# define PRIoLEAST64 __PRI64_PREFIX "o"
# define PRIoFAST8 "o"
# define PRIoFAST16 __PRIPTR_PREFIX "o"
# define PRIoFAST32 __PRIPTR_PREFIX "o"
# define PRIoFAST64 __PRI64_PREFIX "o"
/* Unsigned integers. */
# define PRIu8 "u"
# define PRIu16 "u"
# define PRIu32 "u"
# define PRIu64 __PRI64_PREFIX "u"
# define PRIuLEAST8 "u"
# define PRIuLEAST16 "u"
# define PRIuLEAST32 "u"
# define PRIuLEAST64 __PRI64_PREFIX "u"
# define PRIuFAST8 "u"
# define PRIuFAST16 __PRIPTR_PREFIX "u"
# define PRIuFAST32 __PRIPTR_PREFIX "u"
# define PRIuFAST64 __PRI64_PREFIX "u"
/* lowercase hexadecimal notation. */
# define PRIx8 "x"
# define PRIx16 "x"
# define PRIx32 "x"
# define PRIx64 __PRI64_PREFIX "x"
# define PRIxLEAST8 "x"
# define PRIxLEAST16 "x"
# define PRIxLEAST32 "x"
# define PRIxLEAST64 __PRI64_PREFIX "x"
# define PRIxFAST8 "x"
# define PRIxFAST16 __PRIPTR_PREFIX "x"
# define PRIxFAST32 __PRIPTR_PREFIX "x"
# define PRIxFAST64 __PRI64_PREFIX "x"
/* UPPERCASE hexadecimal notation. */
# define PRIX8 "X"
# define PRIX16 "X"
# define PRIX32 "X"
# define PRIX64 __PRI64_PREFIX "X"
# define PRIXLEAST8 "X"
# define PRIXLEAST16 "X"
# define PRIXLEAST32 "X"
# define PRIXLEAST64 __PRI64_PREFIX "X"
# define PRIXFAST8 "X"
# define PRIXFAST16 __PRIPTR_PREFIX "X"
# define PRIXFAST32 __PRIPTR_PREFIX "X"
# define PRIXFAST64 __PRI64_PREFIX "X"
/* Macros for printing `intmax_t' and `uintmax_t'. */
# define PRIdMAX __PRI64_PREFIX "d"
# define PRIiMAX __PRI64_PREFIX "i"
# define PRIoMAX __PRI64_PREFIX "o"
# define PRIuMAX __PRI64_PREFIX "u"
# define PRIxMAX __PRI64_PREFIX "x"
# define PRIXMAX __PRI64_PREFIX "X"
/* Macros for printing `intptr_t' and `uintptr_t'. */
# define PRIdPTR __PRIPTR_PREFIX "d"
# define PRIiPTR __PRIPTR_PREFIX "i"
# define PRIoPTR __PRIPTR_PREFIX "o"
# define PRIuPTR __PRIPTR_PREFIX "u"
# define PRIxPTR __PRIPTR_PREFIX "x"
# define PRIXPTR __PRIPTR_PREFIX "X"
/* Macros for scanning format specifiers. */
/* Signed decimal notation. */
# define SCNd8 "hhd"
# define SCNd16 "hd"
# define SCNd32 "d"
# define SCNd64 __PRI64_PREFIX "d"
# define SCNdLEAST8 "hhd"
# define SCNdLEAST16 "hd"
# define SCNdLEAST32 "d"
# define SCNdLEAST64 __PRI64_PREFIX "d"
# define SCNdFAST8 "hhd"
# define SCNdFAST16 __PRIPTR_PREFIX "d"
# define SCNdFAST32 __PRIPTR_PREFIX "d"
# define SCNdFAST64 __PRI64_PREFIX "d"
/* Signed decimal notation. */
# define SCNi8 "hhi"
# define SCNi16 "hi"
# define SCNi32 "i"
# define SCNi64 __PRI64_PREFIX "i"
# define SCNiLEAST8 "hhi"
# define SCNiLEAST16 "hi"
# define SCNiLEAST32 "i"
# define SCNiLEAST64 __PRI64_PREFIX "i"
# define SCNiFAST8 "hhi"
# define SCNiFAST16 __PRIPTR_PREFIX "i"
# define SCNiFAST32 __PRIPTR_PREFIX "i"
# define SCNiFAST64 __PRI64_PREFIX "i"
/* Unsigned decimal notation. */
# define SCNu8 "hhu"
# define SCNu16 "hu"
# define SCNu32 "u"
# define SCNu64 __PRI64_PREFIX "u"
# define SCNuLEAST8 "hhu"
# define SCNuLEAST16 "hu"
# define SCNuLEAST32 "u"
# define SCNuLEAST64 __PRI64_PREFIX "u"
# define SCNuFAST8 "hhu"
# define SCNuFAST16 __PRIPTR_PREFIX "u"
# define SCNuFAST32 __PRIPTR_PREFIX "u"
# define SCNuFAST64 __PRI64_PREFIX "u"
/* Octal notation. */
# define SCNo8 "hho"
# define SCNo16 "ho"
# define SCNo32 "o"
# define SCNo64 __PRI64_PREFIX "o"
# define SCNoLEAST8 "hho"
# define SCNoLEAST16 "ho"
# define SCNoLEAST32 "o"
# define SCNoLEAST64 __PRI64_PREFIX "o"
# define SCNoFAST8 "hho"
# define SCNoFAST16 __PRIPTR_PREFIX "o"
# define SCNoFAST32 __PRIPTR_PREFIX "o"
# define SCNoFAST64 __PRI64_PREFIX "o"
/* Hexadecimal notation. */
# define SCNx8 "hhx"
# define SCNx16 "hx"
# define SCNx32 "x"
# define SCNx64 __PRI64_PREFIX "x"
# define SCNxLEAST8 "hhx"
# define SCNxLEAST16 "hx"
# define SCNxLEAST32 "x"
# define SCNxLEAST64 __PRI64_PREFIX "x"
# define SCNxFAST8 "hhx"
# define SCNxFAST16 __PRIPTR_PREFIX "x"
# define SCNxFAST32 __PRIPTR_PREFIX "x"
# define SCNxFAST64 __PRI64_PREFIX "x"
/* Macros for scanning `intmax_t' and `uintmax_t'. */
# define SCNdMAX __PRI64_PREFIX "d"
# define SCNiMAX __PRI64_PREFIX "i"
# define SCNoMAX __PRI64_PREFIX "o"
# define SCNuMAX __PRI64_PREFIX "u"
# define SCNxMAX __PRI64_PREFIX "x"
/* Macros for scaning `intptr_t' and `uintptr_t'. */
# define SCNdPTR __PRIPTR_PREFIX "d"
# define SCNiPTR __PRIPTR_PREFIX "i"
# define SCNoPTR __PRIPTR_PREFIX "o"
# define SCNuPTR __PRIPTR_PREFIX "u"
# define SCNxPTR __PRIPTR_PREFIX "x"
__BEGIN_DECLS
#if __WORDSIZE == 64
/* We have to define the `uintmax_t' type using `ldiv_t'. */
typedef struct
{
long int quot; /* Quotient. */
long int rem; /* Remainder. */
} imaxdiv_t;
#else
/* We have to define the `uintmax_t' type using `lldiv_t'. */
typedef struct
{
__extension__ long long int quot; /* Quotient. */
__extension__ long long int rem; /* Remainder. */
} imaxdiv_t;
#endif
/* Compute absolute value of N. */
extern intmax_t imaxabs (intmax_t __n) __THROW __attribute__ ((__const__));
/* Return the `imaxdiv_t' representation of the value of NUMER over DENOM. */
extern imaxdiv_t imaxdiv (intmax_t __numer, intmax_t __denom)
__THROW __attribute__ ((__const__));
/* Like `strtol' but convert to `intmax_t'. */
extern intmax_t strtoimax (const char *__restrict __nptr,
char **__restrict __endptr, int __base) __THROW;
/* Like `strtoul' but convert to `uintmax_t'. */
extern uintmax_t strtoumax (const char *__restrict __nptr,
char ** __restrict __endptr, int __base) __THROW;
/* Like `wcstol' but convert to `intmax_t'. */
extern intmax_t wcstoimax (const __gwchar_t *__restrict __nptr,
__gwchar_t **__restrict __endptr, int __base)
__THROW;
/* Like `wcstoul' but convert to `uintmax_t'. */
extern uintmax_t wcstoumax (const __gwchar_t *__restrict __nptr,
__gwchar_t ** __restrict __endptr, int __base)
__THROW;
__END_DECLS
#endif /* inttypes.h */
float.h定义了浮点数类型 float、double、long double 的一些宏,规定了这些类型的范围和精度。
FLT_ROUNDS
宏FLT_ROUNDS表示当前浮点数加法的舍入方式。
它有以下可能的值:
FLT_RADIX
宏FLT_RADIX表示科学计数法的指数部分的底(base),一般总是2
!
浮点数类型的最大最小值
(5)两个同类型浮点数之间可表示的最小差值(最小精度)
FLT_EPSILON
DBL_EPSILON
LDBL_EPSILON
(6)DECIMAL_DIG
宏DECIMAL_DIG表示十进制有效位数。
(7)FLT_EVAL_METHOD
宏FLT_EVAL_METHOD表示浮点数运算时的类型转换。
它可能有以下值。
-1:不确定。
0:在当前类型中运算。
1:float 和 double 类型的运算使用 double 类型的范围和精度求值。
2:所有浮点数类型的运算使用 long double 类型的范围和精度求值。
(8)浮点数尾数部分的个数
FLT_MANT_DIG
DBL_MANT_DIG
LDBL_MANT_DIG
(9)浮点数指数部分有效数字的个数(十进制)
FLT_DIG
DBL_DIG
LDBL_DIG
(10)科学计数法的指数部分的最小次幂(负数)
FLT_MIN_EXP
DBL_MIN_EXP
LDBL_MIN_EXP
(11)科学计数法的指数部分的十进制最小次幂(负数)
FLT_MIN_10_EXP
DBL_MIN_10_EXP
LDBL_MIN_10_EXP
(12)科学计数法的指数部分的最大次幂
FLT_MAX_EXP
DBL_MAX_EXP
LDBL_MAX_EXP
(13)科学计数法的指数部分的十进制最大次幂
FLT_MAX_10_EXP
DBL_MAX_10_EXP
LDBL_MAX_10_EXP
头文件math.h提供了一些常用的数学计算函数接口。
// #define NDEBUG
#include <assert.h>
assert(expression);
__FILE__
和__LINE__
这两个编译器预定义的Macro),最后调用abort
结束程序的执行。#include <assert.h>
的语句之前插入#define NDEBUG
来禁用assert调用,或者gcc -DNDEBUG
,这样可以不用大规模修改源码。由于assert被触发后,会调用abort结束程序的执行,有时这反而会不利于程序的调试。自定义类似assert机制的Marco一定也不难,比如下面就是我常用的HOPE系列:
#define HOPE_EQ(a,b) do{\
if(a != b)\
std::cerr<<"HOPE_EQ FAILED "<<__FILE__<<": "<<__LINE__<<std::endl;\
}while(0)
#define HOPE_LE(a,b) do{\
if(a > b)\
std::cerr<<"HOPE_LE FAILED "<<__FILE__<<": "<<__LINE__<<std::endl;\
}while(0)
C11引入了静态断言static_assert,用于在编译阶段进行断言判断。由于只在编译阶段起作用,因此它不能用对变量使用。
static_assert(constant-expression, string-literal);
当第一个参数的值为false时,会产生一条编译错误,第二个参数就是预先定义好的错误提示信息。
C++大量使用static_assert来判断模板的参数是否符合需要。
使用范围:static_assert可以用在全局作用域中,命名空间中,类作用域中,函数作用域中,几乎可以不受限制的使用。
// time() returns the time as the number of seconds
// since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
time_t time(time_t *tloc);
// 返回时间字符串,带\n\0,输入为time_t类型的指针
char *ctime(const time_t *timep);
// 返回时间字符串,带\n\0,输入为struct tm类型的指针
char *asctime(const struct tm *tm);
// 将time_t类型转换成struct tm类型,并且转换为UTC时间
struct tm *gmtime(const time_t *timep);
// 将time_t类型转换成struct tm类型,并且转换为本地当前时间
struct tm *localtime(const time_t *timep);
// 时间字符串格式化接口,format部分参数丰富,请参考manpage
size_t strftime(char *restrict s, size_t max,
const char *restrict format,
const struct tm *restrict tm);
代码示例,请参考:C语言时间计算
头文件ctype.h定义了一批C语言字符类别判断函数(C character classification functions),用于测试字符是否属于特定的字符类别,如字母字符、控制字符等等。
int isalnum(int c) // isalpha(c) or isdigit(c) is true
int isalpha(int c) // isupper(c) or islower(c) is true
int isblank(int c) // space ' ' and horizontal tab \t
int iscntrl(int c) // control character
int isdigit(int c) // decimal digit
int isgraph(int c) // printing character except space
int islower(int c) // lower-case letter
int isprint(int c) // printing character including space
int ispunct(int c) // printing character except sapce or letter or digit
int isspace(int c) // 6 whitespaces
int isupper(int c) // upper-case letter
int isxdigit(int c) // hexadecimal digit
int tolower(int c)
int toupper(int c)
参数类型为int,返回类型也为int,0 is false,1 is true。
在ASCII字符集中,printing characters is from 0x02 to 0x7E。control characters is from 0x00 to 0x1F, and 0x7F。
ptrdiff_t
C99定义了ptrdiff_t
,在stddef.h头文件中。
ptrdiff_t是C/C++标准库中定义的一个与机器相关的数据类型,ptrdiff_t类型变量通常用来保存两个指针减法操作的结果。标准库类型ptrdiff_t与size_t概念一样,ptrdiff_t也是一种与机器相关的类型。size_t是unsigned类型,而ptrdiff_t则是signed整型,通常被定义为long int
。
man 3 errno
The
<errno.h>
header file defines the integer variableerrno
, which is set by system calls and some library functions in the event of an error to indicate what went wrong.
Linux系统调用,或部分库函数(比如sqrt)在失败的时候,会设置这个变量errno。
errno is defined by the ISO C standard to be a modifiable lvalue of type int, and must not be explicitly declared; errno may be a macro.
errno is thread-local
; setting it in one thread does not affect its value in any other thread.
线程中直接使用errno是安全的。
#include <string.h>
// The strlen() function calculates the length of the string pointed to
// by s, excluding the terminating null byte ('\0').
size_t strlen(const char *s);
// The strcpy() function copies the string pointed to by src, including
// the terminating null byte ('\0'), to the buffer pointed to by dest.
// The strings may not overlap, and the destination string dest must be
// large enough to receive the copy. Beware of buffer overruns!
char *strcpy(char *restrict dest, const char *src);
// The strncpy() function is similar, except that at most n bytes of src
// are copied. Warning: If there is no null byte among the first n bytes
// of src, the string placed in dest will not be null-terminated.
char *strncpy(char *restrict dest, const char *restrict src, size_t n);
// The strcpy() and strncpy() functions return a pointer to the
// destination string dest.
// The strcmp() function compares the two strings s1 and s2.
// The locale is not taken into account (for a locale-aware comparison, see strcoll(3)). The comparison is done using unsigned characters.
// strcmp() returns an integer indicating the result of the comparison,
// as follows:
// 0, if the s1 and s2 are equal;
// a negative value if s1 is less than s2;
// a positive value if s1 is greater than s2.
int strcmp(const char *s1, const char *s2);
// The strncmp() function is similar, except it compares only the first
// (at most) n bytes of s1 and s2.
int strncmp(const char *s1, const char *s2, size_t n);
// The strcat() function appends the src string to the dest string,
// overwriting the terminating null byte ('\0') at the end of dest,
// and then adds a terminating null byte.
// The strings may not overlap, and the dest string must have enough
// space for the result.
// If dest is not large enough, program behavior is unpredictable;
// buffer overruns are a favorite avenue for attacking secure programs.
// As with strcat(), the resulting string in dest is
// always null-terminated.
char *strcat(char *restrict dest, const char *restrict src);
// The strncat() function is similar, except that:
// it will use at most n bytes from src; and
// src does not need to be null-terminated if it contains n or more bytes.
// If src contains n or more bytes, strncat() writes n+1 bytes to dest
// (n from src plus the terminating null byte).
// Therefore, the size of dest must be at least strlen(dest)+n+1.
char *strncat(char *restrict dest, const char *restrict src, size_t n);
// The strchr() function returns a pointer to the first occurrence of
// the character c in the string s.
// If not found, return NULL.
char *strchr(const char *s, int c);
// The strrchr() function returns a pointer to the last occurrence of
// the character c in the string s. (reverse)
char *strrchr(const char *s, int c);
// The strstr() function finds the first occurrence of the substring
// needle in the string haystack.
// The terminating null bytes ('\0') are not compared.
// 如果没有在haystack中找到needle,返回NULL。
char *strstr(const char *haystack, const char *needle);
// 输出errnum对应的字符串的指针
char *strerror(int errnum);
// 测试:
#include <stdio.h>
#include <string.h>
int main(){
for(int i=0; i<255; ++i)
printf("%d: %s\n", i, strerror(i));
return 0;
}
// 部分输出:
...
132: Operation not possible due to RF-kill
133: Memory page has hardware error
134: Unknown error 134
135: Unknown error 135
...
#include <string.h>
// The memset() function fills the first n bytes of the memory area
// pointed to by s with the constant byte c.
void *memset(void *s, int c, size_t n);
// The memcpy() function copies n bytes from memory area src to memory
// area dest. The memory areas must not overlap.
// Use memmove(3) if the memory areas do overlap.
void *memcpy(void *restrict dest, const void *restrict src, size_t n);
// The memmove() function copies n bytes from memory area src to memory
// area dest. The memory areas may overlap: copying takes place as
// though the bytes in src are first copied into a temporary array
// that does not overlap src or dest, and the bytes are then copied
// from the temporary array to dest.
void *memmove(void *dest, const void *src, size_t n);
// The memchr() function scans the initial n bytes of the memory area
// pointed to by s for the first instance of c. Both c and the bytes
// of the memory area pointed to by s are interpreted as unsigned char.
// A pointer is returned, which points to the matching byte
// or NULL if the character does not occur in the given memory area.
void *memchr(const void *s, int c, size_t n);
// The memcmp() function compares the first n bytes
// (each interpreted as unsigned char) of the memory areas s1 and s2.
int memcmp(const void *s1, const void *s2, size_t n);
关于memcmp的性能测试
memcmp的实现,应该不会是单个个的char做比较。
引用这个头,就可以方便的使用bool
,true
,false
这几个关键词。
#incldue <stdarg.h>
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
int vprintf(const char *restrict format, va_list ap);
int vfprintf(FILE *restrict stream,
const char *restrict format, va_list ap);
int vdprintf(int fd,
const char *restrict format, va_list ap);
int vsprintf(char *restrict str,
const char *restrict format, va_list ap);
int vsnprintf(char *restrict str, size_t size,
const char *restrict format, va_list ap);
这几个接口的使用,请参考:实现参数数量不定的函数接口
包含此头文件后,C代码就可以使用如下定义,也可以可以提高代码的可读性,这些定义可以在C++环境下直接使用。下面的定义,也是iso646.h文件的全部内容:
#ifndef _ISO646_H
#define _ISO646_H
#ifndef __cplusplus
#define and &&
#define and_eq &=
#define bitand &
#define bitor |
#define compl ~
#define not !
#define not_eq !=
#define or ||
#define or_eq |=
#define xor ^
#define xor_eq ^=
#endif
#endif
本文链接:https://cs.pynote.net/sf/c/202208052/
-- EOF --
-- MORE --