dst = (char *)obstack_blank(&my_obstack, sizeof(int)*2); int a = 100; int b = 200; memcpy(dst, &a, sizeof(int)); memcpy(dst+sizeof(int), &b, sizeof(int));
// 在字符串中查找指定字符 p = (char*) memchr(str, ch, strlen(str)); if (p) { printf("'%c' found at index %ld\n", ch, p - str); } else { printf("'%c' not found\n", ch); }
// 移动节点n1和n2到另一个链表中 list_cut_before(&head2, &head1, &n2->link); printf("The first list after move is: "); print_list(&head1); printf("The second list after move is: "); print_list(&head2);
// 再次移动节点n3到另一个链表中 list_cut_position(&head2, &head1, &n3->link); printf("The first list after second move is: "); print_list(&head1); printf("The second list after second move is: "); print_list(&head2);
printf("The list after adding n1: "); print_list(&head); printf("Is the list empty? %d\n", list_empty(&head)); printf("Is the list empty carefully? %d\n", list_empty_careful(&head));
printf("The list after adding n2: "); print_list(&head); printf("Is the list empty? %d\n", list_empty(&head)); printf("Is the list empty carefully? %d\n", list_empty_careful(&head));
#define list_for_each_entry_safe(pos, n, head, member) for (pos = list_first_entry(head, typeof(*pos), member), n = list_next_entry(pos, member); &pos->member != (head); pos = n, n = list_next_entry(n, member))
#define list_for_each_entry_safe_continue(pos, n, head, member) for (pos = list_next_entry(pos, member), n = list_next_entry(pos, member); &pos->member != (head); pos = n, n = list_next_entry(n, member))
用于从当前节点继续往后遍历链表,并允许在遍历过程中删除或添加节点。
#define list_for_each_entry_safe_from(pos, n, head, member) for (n = list_next_entry(pos, member); &pos->member != (head); pos = n, n = list_next_entry(n, member))
用于从某个节点开始遍历链表,并允许在遍历过程中删除或添加节点。
#define list_for_each_entry_safe_reverse(pos, n, head, member) for (pos = list_last_entry(head, typeof(*pos), member), n = list_prev_entry(pos, member); &pos->member != (head); pos = n, n = list_prev_entry(n, member))
上述示例代码中,我们首先创建了两个链表 a 和 b,然后向链表 a 中添加三个结构体。接着,我们使用 list_move() 函数将节点 s1 从链表 a 移动到链表 b 的头部,使用 list_move_tail() 函数将节点 s2 从链表 a 移动到链表 b 的尾部,最后使用 list_bulk_move_tail() 函数将链表 a 中的所有节点都移动到链表 b 的尾部。
上述演示代码中,我们创建了两个链表 a 和 b,并初始化为空。然后,我们向链表 a 中添加三个结构体,向链表 b 中添加两个结构体,并使用 list_for_each_entry 宏分别遍历两个链表并输出节点数据。
接着,我们使用 list_splice() 函数将链表 b 中的所有节点插入到链表 a 的头部,使用 list_splice_tail() 函数将链表 b 中的所有节点插入到链表 a 的尾部,并使用 list_for_each_entry 宏再次遍历两个链表并输出节点数据,可以看到链表 a 中包含了链表 b 中的所有节点。
接下来,我们使用 INIT_LIST_HEAD 宏重新初始化链表 a 并使用 list_splice_init() 函数将链表 b 中的所有节点插入到链表 a 的头部,使用 INIT_LIST_HEAD 宏重新初始化链表 b 并使用 list_splice_tail_init() 函数将链表 a 中的所有节点插入到链表 b 的尾部,并使用 list_for_each_entry 宏再次遍历两个链表并输出节点数据,可以看到两个链表中的节点顺序已经被重新排列。
intmy_init(void) { int irqs[NR_IRQS]; unsignedlong stime;
printk(KERN_INFO "Initializing module...\n");
/* get IRQ statistics for CPU 0 */ kstat_irqs_cpu(0, irqs, &stime);
/* print IRQ statistics */ printk(KERN_INFO "IRQ statistics for CPU 0:\n"); for (int i = 0; i < NR_IRQS; i++) { if (irqs[i] > 0) { printk(KERN_INFO "IRQ %d: count=%d\n", i, irqs[i]); } }
voidfunc() { printf("Entering func...\n"); longjmp(env, 1); printf("This line will not be executed.\n"); }
intmain() { int ret = setjmp(env); if (ret == 0) { printf("Jumping to func...\n"); func(); } else { printf("Returning from longjmp with value %d\n", ret); } return EXIT_SUCCESS; }
上述程序定义了一个名为 env 的 jmp_buf 类型变量,用于保存当前执行状态。在主函数中,通过调用 setjmp 函数将当前状态保存到 env 中,并返回 0。然后调用 func 函数,该函数打印一条消息并调用 longjmp 函数恢复之前保存的状态,这里传入参数值为 1。由于 longjmp 函数会导致程序跳转到 setjmp 函数继续执行,因此后面的 printf 语句会输出 "Returning from longjmp with value 1"。
/* calculate elapsed time in jiffies and convert to ticks */ end = jiffies; ticks = jiffies_delta_to_clock_t(end - start); printk(KERN_INFO "Elapsed time: %ld ticks\n", (long)ticks);
/* calculate elapsed time in jiffies and convert to milliseconds */ end = jiffies; msecs = jiffies_delta_to_msecs(end - start); printk(KERN_INFO "Elapsed time: %lu ms\n", msecs);
/* calculate elapsed time in jiffies_64 and convert to ticks */ end = jiffies_64; ticks = jiffies64_to_clock_t(end - start); printk(KERN_INFO "Elapsed time: %ld ticks\n", (long)ticks);
/* calculate elapsed time in jiffies_64 and convert to milliseconds */ end = jiffies_64; msecs = jiffies64_to_msecs(end - start); printk(KERN_INFO "Elapsed time: %llu ms\n", msecs);
intmain() { int result; int port = 0; // 串行端口 0 // 从硬件端口中输入 result = inport(port); printf("Word read from port %d = 0x%X\n", port, result); return0; }
4. insline
4.1 函数说明
函数声明
函数功能
void insline(void);
在当前光标位置插入一行空行,原光标所在行及其下方的所有行都会向下移动一行 【在 Turbo C 等早期 C 编译器的图形库或控制台操作库中使用】
4.2 演示示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#include<conio.h>
intmain() { clrscr(); cprintf("INSLINE inserts an empty line in the text window\r\n"); cprintf("at the cursor position using the current text\r\n"); cprintf("background color. All lines below the empty one\r\n"); cprintf("move down one line and the bottom line scrolls\r\n"); cprintf("off the bottom of the window.\r\n"); cprintf("\r\nPress any key to continue:"); gotoxy(1, 3); getch(); // 在文本窗口中插入一个空行 insline(); getch(); return0; }
5. installuserdriver
5.1 函数说明
函数声明
函数功能
int installuserdriver(char *name, int (*detect)(void));
/* 删除文件,成功返回0,失败返回非0。 */ intdelete_file(char near *filename) { unionREGSregs; int ret; regs.h.ah = 0x41; regs.x.dx = (unsigned) filename; ret = intdos(®s, ®s);
// 如果设置了进位标志,则出现错误 return(regs.x.cflag ? ret : 0); }
intmain(void) { int err; err = delete_file("NOTEXIST.$$$"); if (!err) printf("Able to delete NOTEXIST.$$$\n"); else printf("Not Able to delete NOTEXIST.$$$\n"); return0; }
10. intdosx
10.1 函数说明
函数声明
函数功能
int intdosx(union REGS *inregs, union REGS *outregs, struct SREGS *segregs);
它主要作用是触发一个 DOS 软件中断(通常是中断号 0x21),并通过寄存器传递参数和获取返回值,从而实现对 DOS 系统功能的调用。
/* 删除文件,成功返回0,失败返回非0。 */ intdelete_file(char far *filename) { unionREGSregs; structSREGSsregs; int ret; regs.h.ah = 0x41; regs.x.dx = FP_OFF(filename); sregs.ds = FP_SEG(filename); ret = intdosx(®s, ®s, &sregs);
// 如果设置了进位标志,则出现错误 return(regs.x.cflag ? ret : 0); }
intmain(void) { int err; err = delete_file("NOTEXIST.$$$"); if (!err) printf("Able to delete NOTEXIST.$$$\n"); else printf("Not Able to delete NOTEXIST.$$$\n"); return0; }
11. intr
11.1 函数说明
函数声明
函数功能
void intr(int intr_num, struct REGPACK *preg);
它是一个在早期 DOS 环境下用于进行软件中断调用的函数
参数:
int intr_num :要调用的中断号。在 DOS 和 BIOS 系统中,不同的中断号对应着不同的功能。例如,中断号 0x10 通常用于 BIOS 的视频服务,中断号 0x21 用于 DOS 系统功能调用。
printf("Enter directory to change to: "); gets(directory); reg.r_ax = 0x3B << 8; // 将3Bh转换为AH reg.r_dx = FP_OFF(directory); reg.r_ds = FP_SEG(directory); intr(0x21, ®); if (reg.r_flags & CF) printf("Directory change failed\n"); getcwd(directory, 80); printf("The current directory is: %s\n", directory); return0; }
12. ioctl
12.1 函数说明
函数声明
函数功能
int ioctl(int fd, int cmd, ...) ;
控制 I/O 设备
参数:
fd :文件描述符
cmd : 交互协议,设备驱动将根据 cmd 执行对应操作
… : 可变参数arg,依赖 cmd 指定长度以及类型
12.2 演示示例
1 2 3 4 5 6 7 8 9 10 11 12 13
#include<stdio.h> #include<dir.h> #include<io.h>
intmain(void) { int stat = ioctl(0, 8, 0, 0); if (!stat) printf("Drive %c is removable.\n", getdisk() + 'A'); else printf("Drive %c is not removable.\n", getdisk() + 'A'); return0; }
printf("The hypotenuse of a right triangle whose legs are %lf and %lf is %lf\n", x, y, result); printf("The hypotenuse of a right triangle whose legs are %f and %f is %f\n", xf, yf, resultf); printf("The hypotenuse of a right triangle whose legs are %Lf and %Lf is %Lf\n", xL, yL, resultL);
intmain(void) { // 在硬件问题中断上安装我们的处理程序 harderr(handler); clrscr(); printf("Make sure there is no disk in drive A:\n"); printf("Press any key ....\n"); getch(); printf("Trying to access drive A:\n"); printf("fopen returned %p\n", fopen("A:temp.dat", "w")); return0; }