
C语言编程
choumin
这个作者很懒,什么都没留下…
展开
-
目录遍历与too many files open错误
目录遍历与 too many files open 错误原创 2025-02-28 07:35:33 · 151 阅读 · 0 评论 -
使用乘法和位运算求整数除以3的结果
使用乘法和位运算求整数除以 3 的结果。原创 2025-02-16 16:41:44 · 121 阅读 · 0 评论 -
long转float的C语言实现
long 转 float 的 C 语言实现原创 2025-01-05 16:32:54 · 202 阅读 · 0 评论 -
GHashTable基本用法和注意事项
GHashTable 基本用法和注意事项。原创 2024-12-29 10:10:29 · 199 阅读 · 0 评论 -
多线程复杂系统调试利器——assert()
调试复杂系统时,最大的难点在于定位问题,如果弄清楚了问题产生的机理,那么就能有针对性的进行解决原创 2024-09-28 18:16:20 · 303 阅读 · 0 评论 -
C语言中32位浮点数的格式
C语言中32位浮点数的格式原创 2024-07-06 11:13:36 · 861 阅读 · 0 评论 -
在 Linux C 中获得所有环境变量
在 Linux C 中获得所有环境变量 ...原创 2024-04-07 14:39:17 · 498 阅读 · 0 评论 -
openssl测试时指定engine加载目录
在 openssl 测试时指定 engine 加载目录的方法原创 2023-06-20 16:02:34 · 1087 阅读 · 0 评论 -
使用 patchelf 修改 ELF 文件的动态链接器路径
使用 patchelf 修改 ELF 文件的动态链接器路径示例。原创 2023-01-27 14:23:45 · 2360 阅读 · 0 评论 -
灵活使用 C 语言中的宏定义
灵活使用 C 语言中的宏定义示例原创 2023-01-17 20:53:52 · 1450 阅读 · 1 评论 -
指针数组和数组指针的区别及基本用法
下面简单介绍一下它们之间的区别,再进行画图说明,最后给出示例代码。原创 2022-08-20 09:18:31 · 593 阅读 · 0 评论 -
在C语言中自定义调用栈
对于规模大一些的 C 语言项目,往往会存在不好查的 bug,比如某些底层函数在检查参数时遇到不符合预期的情况,但由于调用路径很多,不能有效且快速的找出完整的调用链。此时,如果能在出问题的点打印出调用链,那将会有助于快速定位问题。之前在看 mariadb 的源码时,发现里面实现了自定义的调用栈跟踪功能,下面将其中的关键代码简化出来,以供大家参考。#include <stdio.h>#include <stdlib.h>#include <...原创 2021-12-12 15:42:25 · 748 阅读 · 0 评论 -
使用pthread_key_t存储和索引线程相关数据
在 C 语言多线程编程中,我们经常会在程序的执行过程中用到一些与本线程相关的数据,如果是比较简单的应用,我们可以为每个线程创建一个类似于执行环境的结构体,比如 struct thread_context,专门用来存储与本线程相关的数据,那么在函数调用的时候,我们就需要传递这个结构体指针,或者使用全局的结构体数组来保存每个线程的执行环境,但当某个函数需要使用该结构体时,还是需要一个类似于下标这种东西去索引对应的 struct thread_context,所以,常规的方法还是无法避免传递指针或...原创 2021-12-12 09:55:24 · 397 阅读 · 0 评论 -
GNU C中的可变参宏定义
GNU C 中支持三种形式的可变参宏定义,如下所示:#define debug1(format, ...) fprintf (stderr, format, __VA_ARGS__)#define debug2(format, args...) fprintf (stderr, format, args)#define debug3(format, ...) fprintf (stderr, format, ## __VA_ARGS__)其中,当可变参列表为空时,需要使用第三种定义方式,如原创 2021-03-20 17:14:40 · 216 阅读 · 0 评论 -
C99中的柔性数组成员
C99 支持结构体中包含柔性数组成员,它的基本形式如下:struct data { int a; unsigned long b[];};在使用时,有下面几点要求:1)柔性数组成员需要写成:contents[ ] 的形式;2)由于柔性数组成员的类型不完整,因此无法对该成员进行 sizeof 操作;3)柔性数组成员只能出现在结构体的最后一个位置;使用方法:1)动态分配空间#include <stdlib.h>struct data { i原创 2021-03-10 21:45:46 · 191 阅读 · 0 评论 -
XDR数据类型
1、基本数据类型和 C 语言基本数据类型相似,包括 int、 unsigned int、enum、bool、long、float、double等,使用示例如下:data.x 文件:enum colors {RED = 2, YELLO = 3, BLUE = 5};struct data { int a; unsigned int b; enum colors c; bool d; long e; float f; double g;};rpcgen 生成的 data.原创 2021-03-07 16:09:45 · 2174 阅读 · 0 评论 -
使用glibc xdr对结构体进行编解码
glibc 中的 rpc/xdr.h 提供了很多 xdr_xxx()接口,可以用一种跨平台的方式对任意数据进行编码和表示。下面介绍如何对结构体数据进行跨平台的编码和解码,主要涉及以下几个步骤:1)使用 rpc 语言定义结构体(类似于 thrift 中的 IDL 文件),使用 rpcgen 生成对应的 .h 和 .c 文件2)使用 xdrstdio_create() 初始化 XDR 对象,并调用上述文件自动生成的接口对结构体数据进行编码,得到编码后的内存 buffer3)使用 xdrmem_cr.原创 2021-03-06 23:25:41 · 1454 阅读 · 0 评论 -
fmemopen和open_memstream
glibc 中的 fmemopen() 和 open_memstream() 函数可以实现在一段内存上进行 IO 操作,它们的返回值都是 FILE * 类型,利用这个文件指针,可以调用 fwrite()、fread() 等流操作函数,操作结果可以反映到这段内存中。fmemopen() 使用示例:#include <stdio.h>#include <stdlib.h>#include <string.h>char *write_to_buf(char *原创 2021-03-06 22:11:40 · 2518 阅读 · 0 评论 -
GNU C中的复合语句
在 GNU C 中,复合语句可以像一个表达式一样使用,例如下面的代码:int a = ({ int z; int y = foo (); if (y > 0) z = y; else z = - y; z;});再比如,内核中定义的各种get_xxx()宏:#define get_current_user() \({ \ struct user_struct *__u; \ const str原创 2021-02-26 09:05:40 · 255 阅读 · 0 评论 -
C语言中的#line宏
在 C 语言中, __FILE_ 表示当前正在被编译的源文件名字的字符串字面值,__LINE__ 表示当前源文件行数的十进制常量,而 #line 可以改变上述两个宏的内容,即为其指定新的值。主要有以下两种形式:#linelinenum#linelinenumfilename上述调用将会使编译器认为:下一行源代码的行号是从 linenum 开始,并且,当前的输入文件有 filename 给出。以下为示例代码:#include <stdio.h>int main...原创 2021-02-10 18:01:22 · 4826 阅读 · 0 评论 -
在linux下产生core dump文件
1)、通过 kill() 系统调用给进程发送以下信号时,其默认行为是终止进程和产生 core 文件:SIGBUSSIGFPESIGILLSIGIOTSIGQUITSIGSEGVSIGSYSSIGTRAPSIGUNUSEDSIGXCPUSIGXFSZ2)、abort() 会产生core文件3)、raise() 会产生core文件...原创 2021-01-27 13:36:07 · 634 阅读 · 0 评论 -
gcc中的__attribute__语法
gcc 中的 __attribute__ 可以为变量、函数、标签等指定属性。基本语法:__attribute__ ((attribute-list))1)alias ("target")int var_target;extern int __attribute__ ((alias ("var_target"))) var_alias;为一个对象指定一个别名,其中 var_target 和 var_alias 的类型要一致。2)weakvoid __f () { /* Do s原创 2021-01-21 18:19:10 · 832 阅读 · 0 评论 -
gcc中为变量和函数指定汇编时名称
在gcc中可以通过 asm() 或者 __asm__() 为变量和函数指定其在汇编代码中的名称int foo asm ("myfoo") = 2;int func (int x, int y) asm ("MYFUNC");int func (int x, int y){/* … */}如下所示,如果不指定的话,变量 foo 的汇编时名称是: foo.1724,$ cat ./main.cint main(void) { static int foo = 5 ;原创 2021-01-21 18:15:53 · 437 阅读 · 0 评论 -
linux程序启动时glibc的调用流程
ELF 文件头的 e_entry 项指明了入口地址,可以通过 objdump -f 命令查看 ELF 文件头信息,一般来说,入口地址的就是代码段 _start 符号的起始地址,在 _start 中调用了 libc 中的 __libc_start_main(),该函数的大致流程是:1)判断是否是静态链接库,如果是,则调用 _dl_start_user() ,否则调用 __libc_init_first();2)调用 __libc_csu_init();3)调用 main();4)调用 __GI原创 2021-01-21 13:50:34 · 1363 阅读 · 0 评论 -
GNU C扩展之三元运算符
在 GNU C 扩展中支持这种形式的三元运算符:x ?: y; 它等价于: x ? x : y这两者比较重要的区别是:前者只对表达式 x 进行一次计算,而后者会计算两次,在某些情况下,这种重复计算可能会有副作用:比如:int b = ++a ? ++a : -1;同时,当 x 是一个函数调用时,重复计算还会带来性能的损失,比如:int b = foo() ?: -1; 比 int b = foo() ? foo() : -1; 少调用一次 foo() 函数。在其他语言中也有类似的语法,比如 php原创 2021-01-21 08:46:04 · 252 阅读 · 1 评论 -
gcc中的-D选项
有时候我们想在 C 源文件中使用 Makefile 中定义的某些变量,根据变量的取值做出不同的处理,比如 debug 开关、版本信息等,这时候我们可以通过 gcc 的 -D 选项来满足这一需求,它等同于在 C 文件中通过#define 语句定义一个宏。比如,我们可以在 Makefile 中定义以下变量,并通过 gcc -D 选项传给源文件,然后在源文件中使用这些变量。Makefile:CC=gccversion=0.0.2release_number=2all: testtest...原创 2020-12-27 14:13:08 · 5509 阅读 · 0 评论 -
binutils、gcc和glibc
binutils、gcc 和 glibc 是 GNU 工具链里三个重要的组成部分。binutils 是一系列的二进制工具,最重要的两个工具是:as(汇编器)和 ld(链接器)。as 将 gcc 生成的汇编代码转换为二进制代码,ld 将多个目标文件代码转换为一个库文件或者一个可执行程序。除了 as 和 ld,binutils 还包括ar、nm、objcopy、objdump、readelf 等工具。gcc 是工具链中的编译器套装,目前不仅支持 C 语言,还支持C++, Java, Fortran,..原创 2020-12-27 00:04:22 · 549 阅读 · 1 评论 -
文件描述符和文件指针的区别
文件描述符是一个内核级的整形数值,用来表示一个打开的文件,由open()、creat()、dup()、pipe() 等系统调用获得,由read()、write() 等系统调用来使用。文件描述符不带缓存功能,在可移植性和读写效率方面存在一定的问题。文件指针是一个C标准库的结构体指针,用来表示一个文件。文件指针封装了文件描述符,由fopen()等系统调用获得,由fread()、fwrite()等系统调用使用。文件指针是一个更高级别的接口,具有缓存功能,以及错误标示和EOF检查等功能,具有更好的可移植性和读写效原创 2020-12-25 10:55:46 · 460 阅读 · 1 评论 -
C语言中的旧式函数声明语法
在看UnixBench源码的时候,看到这样一个函数:void wake_me(seconds, func) int seconds; void (*func)();{ /* set up the signal handler */ signal(SIGALRM, func); /* get the clock running */ alarm(seconds);}这个函数在定义的时候,参数部分是不是看着有点陌生?查了一下,这其实是C语言中一种老原创 2020-12-24 10:30:04 · 2403 阅读 · 0 评论 -
C99中的可变长数组
在C99标准中开始支持可变长数组,即在声明数组时可以用变量来指示数组的大小,而不一定是常量表达式。看下面的示例程序:#include <stdio.h>int main(int argc, char **args) { int n = 5; if (argc > 1) { n = atoi(args[1]); } double A[n][n]; typeof(A) B; printf("sizeof B[%d][%d]:原创 2020-12-22 20:48:33 · 1547 阅读 · 0 评论 -
make内置函数之流程控制
make中主要有下面几个与流程控制相关的内置函数1)if 函数根据condition的值选择then-part和else-part中的某一个宏扩展,其中,如果condition的宏扩展中包含任意字符(包括空格),那么condition的值为true,在这种情况下,then-part被展开,否则如果condition 的宏扩展为空,那么condition的值为false,else-part被展开。$(if condition, then-part, else-part)2)error 函数用来原创 2020-12-22 11:06:31 · 208 阅读 · 0 评论 -
make内置函数之文件名处理
make中主要有下面几个与文件名处理相关的内置函数1)wildcard 函数接受一个pattern列表,并对每个pattern进行扩展,最后返回与之匹配的文件名。$(wildcard pattern ...)2)dir 函数返回list中每个文件的目录部分。$(dir list ...)3)not-dir 函数返回name中每个文件的文件名部分。$(not-dir name ...)4)suffix 函数返回name中每个文件的后缀部分。$(suffix name .原创 2020-12-22 11:03:32 · 202 阅读 · 0 评论 -
make内置函数之字符串处理
make中主要有下面几个字符串处理相关的内置函数1)filter 函数会将text视为一系列被空格隔开的单词,会返回与pattern匹配的单词。$(filter pattern ..., text)2)filter-out 函数所做的事情刚好跟filter相反,用来选出与pattern不匹配的单词。$(filter-out pattern ..., text)3)findstring 函数用来在text中查找string,如果string被找到了,那么该函数返回string,否则返回原创 2020-12-22 10:58:19 · 439 阅读 · 0 评论 -
make内置函数call
在make中,内置函数call用来扩展变量或者宏,它的语法如下:$(call macro-name[, param1 ...])call会扩展它的第一个参数并把其余参数依次替换到出现$1、$2 ......的地方,macro-name 可以是任何宏或变量的名称。macro-name之后是宏的参数,并以逗号为分隔符。call的第一个参数是一个非扩展式变量名称,即它并非以一个美元符号开始。call的参数检查机制非常简单,你可以为call指定任意多个参数。如果一个宏引用了一个参数$n,但是调用它的ca原创 2020-12-22 10:48:31 · 1627 阅读 · 0 评论 -
make中的自动变量
make中主要有以下几个自动变量$@ 目标的文件名$% 库文件成员结构中的文件名元素库文件中某个成员也可以作为目标,形如:archive(member),例如:如果目标是foo.a(bar.o),那么 $% 是bar.o,而 $@ 是foo.a$< 第一个依赖的文件名$? 时间戳大于目标的所有依赖项,以空格隔开$^ 所有依赖项的文件名,以空格隔开,已去重$+ 如同$^,未去重$* 目标的主文件名...原创 2020-12-22 08:46:40 · 295 阅读 · 0 评论 -
GNU C中数组指定初始化
在GNU C中,数组支持指定初始化。简单来说,就是在初始化数组和结构体时,可以通过指定数组下标或者具体成员名来赋初值。例如支持下面这样的初始化:int array[6] = { [4] = 29, [2] = 15 }; // 可以不按顺序赋值还支持将数组中指定范围内的元素赋值为相同的值:int array[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };利用这个特性,我们可以在申请数组的同时进行初始化,比如全部清零:int a原创 2020-12-21 20:51:32 · 875 阅读 · 0 评论 -
C语言中带参数宏的展开次序
最近看QEMU代码的机会比较多,发现里面用了大量宏定义,有必要学习一下。刚开始主要关注了带参数宏的宏展开次序,发现了之前没有注意到的东西。一般而言,我们在调用一个带参数宏时,如果传入的参数也是一个带参数宏的话,我们期待的是像函数调用那样,从内层到外层依次展开,依次计算出结果后,将内层宏展开后的结果作为实参交给更外层的宏进行处理,因为我们认为最内层的括号优先级最高,应该被优先处理。大多数情况下,这个结论是正确的,但如果外层的宏展开后有 '#' 或 "##" 运算符操作,则会优先从该层展开,这种情况下,在宏原创 2020-11-22 15:49:39 · 1487 阅读 · 0 评论 -
C语言强制类型转换小问题
想必很多同学都在C语言中使用过强制类型转换,不知道有没有碰到什么问题。如果谨慎使用强制类型转换,大多数时候都不会出错。当然,前提是对C语言的内存布局比较熟悉,否则有时候看着语法和逻辑都没有问题,却有可能出现意想不到的问题。看下面这段代码,猜猜输出结果是什么: 1 #include <stdio.h> 2 3 void *a = 0; 4 5 void set(void *p) { 6 a = p; 7 printf("a has原创 2020-11-08 15:48:56 · 593 阅读 · 0 评论 -
在makefile中使用shell命令
如果不需要进行特别复杂的逻辑处理,只要知道一些基本规则就可了。它们主要是:在Makefile中执行shell命令时,是一行创建一个进程来执行。 在命令前使用'@'来控制不在屏幕上打印正在执行的命令。下面是一个简单的示例all: copy_configcopy_config: @if [ ! -d "/etc/abc/" ]; then \ mkdir -p /etc/abc; \ fi; \ cp ./conf/* /etc/abc/...原创 2020-10-05 14:29:45 · 1784 阅读 · 0 评论 -
C语言实现整型字符串相乘
好长时间没写C程序了,现在来实现一个整型字符串相乘的小功能。看代码,欢迎拍砖。#include <string.h>#include <sys/malloc.h>#include <stdio.h>#include <stdlib.h>void reverse(char *a) { int n = strlen(a), i = 0, tmp = 0; for (i = 0; i < n / 2; ++i) { tmp = a[i原创 2020-05-16 10:38:43 · 3399 阅读 · 0 评论