C 代码片断

来自百合仙子's Wiki
(重定向自C代码片断
跳转到导航 跳转到搜索

变长参数

void fatal(char *fmt, ...){
  va_list argp;
  fprintf(stderr, "Fatal: ");
  va_start(argp, fmt);
  vfprintf(stderr, fmt, argp);
  va_end(argp);
  fprintf(stderr, "\n");
  exit(-1);
}

来源:Variable-Length Argument Lists

volatile 关键字

可用mmap(2)实现自动变化的变量。使用gcc加优化参数编译,则为死循环。注意 while 循环体必须为空。

#include<stdio.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>
#include<fcntl.h>

int main(int argc, char **argv){
  int *p;
  int fd = open("test", O_RDWR);
  if(fd < 0){
    perror("open test");
    exit(1);
  }
  p = mmap(NULL, 4, PROT_WRITE, MAP_SHARED, fd, 0);
  if(p == MAP_FAILED){
    perror("mmap");
    exit(1);
  }
  close(fd);
  while(*p != 3);
  munmap(p, 4);

  return 0;
}

辅助程序,它从外部来改变上一个程序变量 *p 的值

#include<stdio.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>
#include<fcntl.h>

int main(int argc, char **argv){
  int *p;
  int fd = open("test", O_RDWR);
  if(fd < 0){
    perror("open test");
    exit(1);
  }
  p = mmap(NULL, 4, PROT_WRITE, MAP_SHARED, fd, 0);
  if(p == MAP_FAILED){
    perror("mmap");
    exit(1);
  }
  close(fd);
  for(fd=0; 1; fd++){
    *p = fd;
    sleep(1);
  }
  munmap(p, 4);

  return 0;
}

信号

收到信号时打印函数栈并退出:

void SetMyExceptionHandler(){
  int signo;

  for(signo = SIGHUP; signo < SIGUNUSED; signo++){
    signal(signo, OnException);
  }
}

void OnException(int signo){
  if(signo == SIGCHLD)
    return;

  if(signo == SIGCONT)
    return;

  void *array[10];
  size_t size;
  char **strings = NULL;
  size_t i;

  size = backtrace(array, 10);
  strings = backtrace_symbols(array, size);

  if(strings){
    FILE *fp = NULL;
    fp = fopen("/home/lilydjwg/tmpfs/mb_crash.log", "w");

    printf("Obtained %zd stack frames.\n", size);
    if(fp){
      fprintf(fp, "mb -- Get Signal No. %d\n", signo);
      fprintf(fp, "Obtained %zd stack frames.\n", size);
    }

    for(i = 0; i < size; i++){
      printf("%s\n", strings[i]);
      if(fp)
	fprintf(fp, "%s\n", strings[i]);
    }

    if(fp)
      fclose(fp);
    free(strings);
  }

  exit(128+signo);
}

来自fcitx的源代码。

LD_PRELOAD

重定向文件打开操作,使用 Lua 控制实际打开的文件:

#include <stdarg.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

static int lib_initialized = 0;
static int (*orig_open)(const char*, int, mode_t) = 0;
static int (*orig_open64)(const char*, int, mode_t) = 0;
void lib_init();

void die(char *fmt, ...) {
  va_list args;
  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
  va_end(args);
  fprintf(stderr, "\n");
  fflush(stderr);
  exit(-1);
}

int open(const char* file, int flags, mode_t mode) {
  lib_init();
  fprintf(stderr, "opening %s\n", file);
  return orig_open(file, flags, mode);
}

int open64(const char* file, int flags, mode_t mode) {
  lib_init();
  fprintf(stderr, "open64ing %s\n", file);
  return orig_open64(file, flags, mode);
}

void lib_init() {
  void *libhdl;
  char *dlerr;

  if (lib_initialized) return;

  if (!(libhdl=dlopen("libc.so.6", RTLD_LAZY)))
    die("Failed to patch library calls: %s", dlerror());

  orig_open = dlsym(libhdl, "open");
  if ((dlerr=dlerror()) != NULL)
    die("Failed to patch open() library call: %s", dlerr);

  orig_open64 = dlsym(libhdl, "open64");
  if ((dlerr=dlerror()) != NULL)
    die("Failed to patch open64() library call: %s", dlerr);

  lib_initialized = 1;
}

编译参数:

gcc -shared openredir.c -o openredir.so -ldl

大数及高精度计算

求第一个百万位的斐波那契数的各位数字之和:

#include<stdio.h>
#include<stdlib.h>
#include<gmp.h>
#include<mpfr.h>

int main(int argc, char **argv){
  mpz_t a, b;
  mpfr_t c, d;
  mpz_inits(a, b, 0);
  mpfr_inits(c, d, NULL);
  unsigned long n = 4761900;
  mpz_fib2_ui(a, b, n);
  
  /* may be not so accurate... */
  while(mpfr_set_z(c, a, MPFR_RNDA), mpfr_log10(d, c, MPFR_RNDA), mpfr_cmp_ui(d, 999999) < 0){
    mpz_add(b, a, b);
    mpz_swap(a, b);
    n++;
  }
  char *r = mpz_get_str(NULL, 10, a);
  int sum = 0;
  int i;
  for(i=0; i<1000000; i++){
    sum += r[i] - '0';
  }
  mpz_out_str(stderr, 10, a);
  printf("F(%lu)=%d\n", n, sum);
  return 0;
}

参见