C Library

Table of Contents

1 math

  • ceil(2.5)
  • floor(2.5)
  • round(2.5)

2 signal.h

signal

/**
 * sig
 * SIGABRT Signal Abort 中止
 * SIGFPE Floating-Point-Exception 浮点数异常
 * SIGILL Illegal Instruction 不合法指令
 * SIGINT Interrupt 中断
 * SIGSEGV Segmentation Violation 段错误
 * SIGTERM Terminate 中止
 * SIGPIPE Broken pipe 管道错误
 */

/**
 * `SIGPIPE`: one process open a pipe or FIFO for reading before another wrote to it.
 If the reading process never starts, or terminates unexpectly, writing to it raises SIGPIPE.
 Or output to a socket that isn't connected.
 */

/**
 * func
 * SIG_DFL default
 * SIG_IGN Ignore
 * customize: void handler_function(int parameter)
 */
void (*signal(int sig, void (*func)(int))) (int);

3 socket

3.1 API

socket

// domain: AF_INET(IPv4), AF_INET6(IPv6)
// type: SOCK_STREAM, SOCK_DGRAM
// protocol: end-to-end protocol. IPPROTO_TCP, IPPROTO_UDP
int socket(int domain, int type, int protocol);

inet_pton

// src: "192.168.1.1"
// dst: *数字
inet_pton(int addressFamily, const char *src, void *dst);

inet_ntop

// 数字 => "192.168.1.1"
// socklen_t: INET_ADDRSTRLEN IPv4可能最长的结果字符串(字节)
const char *inet_ntop(int addressFamily, const void *src, char *dst, socklen_t dstBytes);

htons

// convert hostshort from host byte order to network byte order.
uint16_t htons(unit16_t hostshort);

connect

// foreignAddr: (struct sockaddr *)&[sockaddr_in]
// addressLength: sizeof(struct sockaddr_in);
int connect(int socket, const struct sockaddr *foreignAddress, socklen_t addressLength);

3.1.1 Server

bind

int bind(int socket, struct sockaddr *localAddress, socklen_t addressSize);

listen

// 告诉TCP实现允许来自客户的连接
// 调用之前,任何连接请求被无声拒绝
int listen(int socket, int queueLimit);

accept

// 使套接字队列中的下一条连接出队。若队列空,则阻塞。
int accept(int socket, struct sockaddr *clientAddress, socklen_t *addressLength);
// 正确的使用方式:
struct sockaddr_storage address;
socklen_t addrLength = sizeof(address);
int clntSock = accept(sock, &address, &addressLength);
// 其中结构体定义如下
struct sockaddr_storage {
  sa_familiy_t
  ... // Padding and fields to get correct length and allignment
}; // 通用地址存储器

send

// 默认阻塞到发送了所有的数据为止。
// 返回:发送的字节数
// flags:改变默认行为。默认为0.
ssize_t send(int socket, const void *msg, size_t msgLength, int flags);

recv

// 默认阻塞到至少传输了一些字节为止。
// 返回:接受的字节数
ssize_t recv(int socket, void *rcvBuffer, size_t bufferLength, int flags);

3.2 Code Snippets

3.2.1 TCP client

#include <stdlib.h>
#include <stdio.h>
#include <string.h> // for memset
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h> // for IPPROTO_TCP
#include <unistd.h> // for close. use `man close`
#include <arpa/inet.h>

#define BUFFER_SIZE 30

int main() {

  // 创建socket
  int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  // 构造servAddr
  char *servIP = "127.0.0.1";
  in_port_t servPort = 8080;
  struct sockaddr_in servAddr;
  memset(&servAddr, 0, sizeof(servAddr));
  servAddr.sin_family = AF_INET;
  // IP地址格式转换
  inet_pton(AF_INET, servIP, &servAddr.sin_addr.s_addr);
  servAddr.sin_port = htons(servPort);

  // 建立连接
  connect(sock, (struct sockaddr *)&servAddr, sizeof(servAddr));

  char str[] = "Hello";
  size_t size = strlen(str);
  // 发送数据
  send(sock, str, size, 0);

  char buffer[BUFFER_SIZE];
  // 接收返回的数据,放到buffer里
  recv(sock, buffer, BUFFER_SIZE-1, 0);

  // 关闭socket
  close(sock);

}

3.2.2 TCP server

#include <stdlib.h>
#include <stdio.h>
#include <string.h> // for memset
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h> // for IPPROTO_TCP
#include <unistd.h> // for close. use `man close`

#define BUFSIZE 30

void handle(int clntSock) {
  char buffer[BUFSIZE];
  // 从client端socket接收数据,存入buffer,返回接受长度。一次只收BUFSIZE个字节。
  ssize_t numBytesRcvd = recv(clntSock, buffer, BUFSIZE, 0);
  // 循环接收直到收完为止。
  while(numBytesRcvd>0) {
    // 将接收到的buffer,send到client端buffer
    send(clntSock, buffer, numBytesRcvd, 0);
    // 接着接收没收完的。
    numBytesRcvd = recv(clntSock, buffer, BUFSIZE, 0);
  }
  // 关闭socket
  close(clntSock);
}

int main(){
  // 创建socket
  int servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  // 构造servAddr
  in_port_t servPort = 8080;
  struct sockaddr_in servAddr;
  memset(&servAddr, 0, sizeof(servAddr));
  servAddr.sin_family = AF_INET;
  servAddr.sin_addr.s_addr = htonl(INADDR_ANY); // any incoming interface
  servAddr.sin_port = htons(servPort);

  // socket绑定到servAddr
  bind(servSock, (struct sockaddr *)&servAddr, sizeof(servAddr));

  // 监听socket
  listen(servSock, 5);

  for(;;) {
    struct sockaddr_in clntAddr;
    socklen_t clntAddrLen = sizeof(clntAddr);
    // 接受socket来的请求,把来的socket存入clntSock
    int clntSock = accept(servSock, (struct sockaddr *)&clntAddr, &clntAddrLen);
    // 处理之
    handle(clntSock);
  }
}

4 stdio

4.1 stdio.h

perror

void perror(const char *str);

fflush

int fflush(FILE *stream);

fopen

FILE *fopen(const char *filename, const char *mode);

fclose

int fclose(FILE *stream);

freopen

FILE *freopen(const char *filename, const char *mode, FILE *stream);

fprintf

int fprintf(FILE *stream, const char *format, ...);

fscanf

int fscanf(FILE *stream, const char *format, ...);

4.2 examples

#include <stdio.h>

int main() {
  FILE* p = fopen("a.txt", "w");
  fprintf(p, "hello");
  fclose(p);
}

5 stdlib

5.1 stdlib.h

malloc

// Allocates a block of size bytes of memory. Not initialized.
void *malloc(size_t size);

free

void free(void *ptr);

calloc

// 为一个num个元素的数组分配内存。每一个有size字节,初始化为0。
void *calloc(size_t num, size_t size)

realloc

// 将ptr指向的block的大小改为size。
// 可能会将这个block移动到一个新的地址。
// block的内容会保留新的大小和旧的大小中较小者。
// 如果新的大小更大,那么多出来的是未定义的。
// 如果ptr==NULL,等价于malloc
void *realloc(void *ptr, size_t size);

atoi

int atoi(const char *str);

atof

double atof(const char *str);

atol

long int atol(const char *str);

strtol

// base是进制
long int strtol(const char *str, char **endptr, int base)

Example:

char str[] = "2001 60cf2d -1100110010 0x6fff";
long int a,b,c,d;
char *sp;
a = strtol(str, &sp, 10);
b = strtol(sp, &sp, 16);
c = strtol(sp, &sp, 2);
d = strtol(sp, NULL, 0);

strtoul

unsigned long int strtoul(const char *str, char **endptr, int base);

strtod

double strtod(const char *str, char **endptr);

printf

// Format: %[flags][width][.precision][length]specifier

/**
 * specifier
 * d/i 有符号十进制整数
 * u 无符号十进制整数
 * o 无符号八进制
 * x 无符号十六进制整数
 * X 同上,但是X大写
 * f/F 浮点数 小写/大写
 * e/E 科学计数法 小写/大写
 * g/G use the shortest representation: (%e or %f / %E or %F)
 * p pointer address
 */

/**
 * Flags
 * - 左对齐
 * + 强制显示+-号
 * (space) 如果没有符号位可写,加空格
 * # (oxX)会打出(0,0x,0X), (aef)会打出小数点
 */

/**
 * width
 * (number) number较大将显示的位数补空格。number小则无影响
 * * 在...中给出
 */

/**
 * .precision
 * (number) (ef)保留位数。s打印个数
 * (.*) ...中给出
 */

/**
 * length
 * l long
 * h short
 * U long long
 * z size_t
 */

int printf(const char *format, ...);

5.2 realpath

#include <limits.h>
#include <stdlib.h>
char *realpath(const char *path, char *resolved_path);

Resolve symbolic link, . ... If resolved_path is NULL, it will malloc and return the pointer. The caller is responsible to free it.

On error, the return value is NULL, and errno is set.

But, it does not check if the file actually exists or not!

5.3 sys/time.h

gettimeofday

// tzp = NULL
// 返回从1970.1.1 00:00 UTC 到现在的秒数
int gettimeofday(struct timeval *tp, void *tzp);
struct timeval {
  __time_t tv_sec;
  __suseconds_t tv_usec;
}

6 strings.h

strcasecmp

// 忽略大小写。比较所有字节。
// 返回:s1>s2: >0
//      s1=s2: =0
//      s1<s2: <0
int strcasecmp(const char *s1, const char *s2);

strncasecmp

// 比较前n个字节
int strncasecmp(const char *s1, const char *s2, size_t n);

strlen

// ssize_t: signed int(POSIX)
// size_t: unsigned int
size_t strlen(const char *str);

7 unistd

getopt

/*
 * optstring:
 *   单个字符 => 选项
 *   单字符: => 选项后须跟参数,且可隔空格可不隔
 *   单字符:: => 选项后须跟参数,必须紧跟,无空格
 *
 * 全局变量
 *   char *optarg => 指向选项参数的指针
 *   int optind => 再次调用时,从此处开始分析
 *   int optopt => 最后一个已知选项
 */
int getopt(int argc, char* const argv[], const char *optstring);

example

  #include <unistd.h>
  int bflag, ch, fd;

  bflag = 0;
  while ((ch = getopt(argc, argv, "bf:")) != -1) {
    switch (ch) {
    case 'b':
      bflag = 1;
      break;
    case 'f':
      if ((fd = open(optarg, O_RDONLY, 0)) < 0) {
        (void)fprintf(stderr,
                      "myname: %s: %s\n", optarg, strerror(errno));
        exit(1);
      }
      break;
    case '?':
    default:
      usage();
    }
   }
  // updates argc and argv to point to the rest of the arguments (- options skipped).
  argc -= optind;
  argv += optind;

7.1 readlink

Follow symbolic link of path, get result into buf. Will fail (return -1) if path is not a symbolic link. Do not use this function to get the absolute path. Use realpath instead.

However, the shell utility works, realpath -f ./some/path will produce the absolute path. But realpath can also do this, so do NOT use this.

ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize);

Usage

if ((len = readlink("/modules/pass1", buf, sizeof(buf)-1)) != -1) {
  buf[len] = '\0';
}