![](https://img-blog.csdnimg.cn/20201014180756930.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
C
文章平均质量分 84
imred
天下事有难易乎?为之,则难者亦易矣;不为,则易者亦难矣。人之为学有难易乎?学之,则难者亦易矣;不学,则易者亦难矣。
展开
-
localhost还是127.0.0.1,这是一个问题(并不是)
(本文内容仅针对Linux环境,内核版本4.15,thrift版本0.11.0,glibc版本2.27)localhost比127.0.0.1快?有江湖传言称,“使用localhost访问本机服务比使用127.0.0.1要快”,这有没有道理呢?自然是没有道理的,除了个别的特例(如https://www.php.net/mysql_connect)因为会对localhost做特殊处理(使用UNIX domain socket替代TCP socket)所以可能快一点(存疑,未验证)外,其他情况使用loca原创 2020-07-29 22:59:27 · 1752 阅读 · 0 评论 -
Linux C/C++调试之五:程序运行耗时的组成
分析程序出现的启动缓慢、响应缓慢和操作卡顿等性能问题时,第一步不该是打开代码编辑器浏览我们的代码,而是首先确定问题是否发生在我们的代码中,简单点的方法就是打开top做一个大致的判断,看一看各CPU的us、sy、id耗时的占比都是多少。进一步来讲,我们需要确定时间都花到什么地方了,是我们的代码中?内核中?还是进程睡大觉的地方?现在假设我们的程序运行在一个CPU资源丰富的环境中,因此就不考虑进程争夺C...原创 2020-01-11 23:00:24 · 1628 阅读 · 0 评论 -
Linux C/C++调试之一:利用LD_PRELOAD机制监控程序IO操作
引言有时,我们为了分析程序的某些问题(例如性能问题),需要对程序的IO操作的频率耗时等数据进行监控。就以经常调用的read和write函数为例,如何监控程序中所有上述两种操作,同时进行计时呢?使用gdb打断点自然是个方法,这样可以很容易发现程序中所有的调用,但是这样就没办法计时了。如果在程序中所有read/write函数前后打上时间戳,就可以实现计时了,但是这会有另一个问题,我们可能调用了某些...原创 2018-07-18 22:52:37 · 2603 阅读 · 0 评论 -
gdb的watchpoint在系统调用中被修改似乎不会被触发
今天遇到一个越界写问题,覆盖了栈底的金丝雀值,导致运行时报“*** stack smashing detected ***”。一开始尝试用gdb的watchpoint定位,但就是眼睁睁的看着运行结束后金丝雀值被修改而没有触发watchpoint,最后无奈一行行的定位,发现是一个ioctl导致的越界写。 后来我试着研究watchpoint未被触发的原因,在GDB的官方Wiki发现这么一句话:...原创 2018-09-09 22:54:39 · 1169 阅读 · 0 评论 -
Linux下对input设备调用ioctl时指定EVIOCGBIT选项时的缓冲区该多大
我们有时候需要获取/dev/input目录下的eventX设备支持哪些事件(EV_KEY、EV_REL和EV_ABS等),可以通过ioctl调用指定EVIOCGBIT(ev, len)选项来获取,例如:ioctl(fd, EVIOCGBIT(0, EV_MAX), buf);来获取fd设备支持的事件。这涉及到一个问题:buf需要指定多大的长度? EVIOCGBIT宏的第二个参数是事件标志...原创 2018-09-12 22:57:26 · 3728 阅读 · 2 评论 -
cmake构建C++项目避免编译时对第三方库头文件进行依赖检查
最近有同事反应一个使用cmake构建的C++项目编译很慢,具体表现是随便修改一个很简单的cpp源文件后,重新编译生成可执行文件的时间需要用3分钟左右。统计了一下整个增量编译过程各阶段耗时,发现时间主要消耗在了cmake生成依赖规则和make检查依赖规则上。生成的依赖规则文件depend.make有200M左右,包含依赖规则条目有100W行以上。所以生成依赖规则和检查依赖都会消耗大量时间。进一步分析...原创 2018-11-06 00:09:46 · 5499 阅读 · 0 评论 -
在Linux下实现一个使用键盘控制的虚拟鼠标
在Linux下创建一个虚拟鼠标设备还是比较简单的,使用内核uinput模块提供的函数即可。创建出虚拟鼠标以后,在主线程监听键盘的事件,当特定的键(此处使用了小键盘的数字键8、2、4、6)被按下或弹起后,进行记录。在另一个线程根据主线程记录的flag创建输入事件,然后将输入事件写入虚拟鼠标设备即可。在实现程序时一个让我思考时间比较长的问题是:是否需要另外创建一个线程来写虚拟鼠标设备。当一个键被按下...原创 2018-11-11 21:48:24 · 3789 阅读 · 1 评论 -
linux下鼠标事件丢失与evdev缓冲区溢出问题
之前遇到这样一个bug:在一个性能较差的linux平台上的一个Qt程序,当UI线程在执行耗时操作时,界面会卡顿,而这时频繁点击滑动鼠标,会出现鼠标事件丢失的问题。举个例子:某个控件收到一个鼠标按下的事件,但再也没有收到鼠标弹起事件,而此时鼠标按键实际上已经弹起了,这就导致程序进入了一种异常状态,除非再次点击鼠标,否则无法恢复。上面这个问题是在QApplication的事件过滤器中确定的,全局的QA...原创 2018-12-15 17:33:18 · 1045 阅读 · 2 评论 -
一次尝试使用cmu sphinx做语音识别的失败记录
好好的C++不去写,为啥想起来搞什么语音识别?事情是这样的,我经常躺在床上听歌,使用电脑连音响播放,因为我比较懒,切歌啥的都直接召唤小娜帮我做,可以节省体力。然而小娜笨啊,除了能切歌啥也干不了,我要是听到一首好听的,还得爬起来去收藏,这多么麻烦是不是?小娜也没开放啥接口可以自定义命令,就想自己写一个程序,识别到我的指令后,按照播放器的快捷键虚拟键盘按键事件。网上一搜“开源语音识别引擎”,好,就是...原创 2018-12-24 00:20:57 · 2535 阅读 · 1 评论 -
Linux C/C++调试之二:使用strace追踪程序系统调用
在之前的一篇文章中,我介绍了一种调试手段:利用LD_PRELOAD机制,拦截动态链接器对动态库的符号解析,达到监控程序IO的目的。事实证明我还是太naive了,我们大可利用现成的工具——strace,来更好地完成这一项工作。strace不只能跟踪程序IO,它能跟踪程序的所有系统调用,实现的基本手段是ptrace系统调用,不过实现细节还没研究过,今天只总结一下它的用法。首先用strace来跟踪一...原创 2019-03-02 18:27:42 · 2866 阅读 · 0 评论 -
ptrace系统调用的实现
最近遇到这样一个问题,机器跑着跑着画面冻结了,打开top看到Xorg的cpu占用率100%。想用gdb挂上去看一下,结果gdb一直卡着挂不上去。后来又换用perf分析,结果发现进程99%的时间花在了一个ioctl调用。这个ioctl操作的是nvidia显卡,进程实际上是卡在了nvidia的驱动中。我对gdb挂不上去这件事感到很好奇,之前除了因为进程已经被另一个gdb调试而导致gdb挂不上去之外,...原创 2019-05-12 15:32:28 · 2690 阅读 · 0 评论 -
gettimeofday和clock_gettime是不是系统调用?
在《Linux多线程服务端编程》一书5.1节中提到过,在x86-64的Linux上,gettimeofday不是系统调用,不会陷入内核。其实这种说法有点小问题,因为gettimeofday确实是个系统调用,但是linux的vdso(virtual dynamic shared object)机制帮我们做到了在调用这些系统调用时不陷入内核,从而提高了性能。vdso机制说白了就是在用户空间帮我们实现...原创 2019-08-25 16:13:07 · 6086 阅读 · 1 评论 -
使用googletest测试可能断言或导致进程退出的函数
做单元测试,一般是验证函数输出数据与预期是否相符。但是也有例外,我们可能需要验证函数在接收到非法参数时是否会断言或抛异常,例如下面这个例子:int foo(int *p){ assert(p != nullptr); return *p;}当传给foo的实参为nullptr时,运行的预期结果就是断言后进程异常退出。这在单元测试中如何验证呢?如何不让这些验证异常值的用例干扰...原创 2019-08-26 23:41:56 · 2336 阅读 · 0 评论 -
Linux C/C++调试之三:性能分析工具callgrind的使用
callgrind是valgrind工具套件中用于分析程序性能的一个工具,它能够得到粒度为函数、代码行和指令级别的性能数据,具体来说,我们可以得到某个函数、某行代码、某条指令处累计执行了多少条指令。我们看一个实例:// foo.cppint accumulate(int begin, int end){ int result = 0; for (int i = begin;...原创 2019-09-01 21:13:55 · 3767 阅读 · 0 评论 -
Linux C/C++调试之四:callgrind的局限
在上篇文章中我介绍了callgrind的大致用法,可以看出来,callgrind是一个非侵入式的,使用起来也很傻瓜的调优工具。初用时感觉这个工具非常趁手,是个程序都想用callgrind去分析一下。但深入使用后发现,callgrind不是银弹,它还是有一些缺陷的。这些缺陷的根源在于:callgrind使用指令数来衡量性能,而程序员用耗时来衡量性能,指令数与耗时仅仅是一个正相关的关系,而非成比例的关...原创 2019-09-01 23:49:51 · 1849 阅读 · 1 评论 -
Linux可用内存充足时进程常驻内存被淘汰的问题
最近遇到这样一个问题:生产环境的某个C++ GUI程序界面时常出现卡顿问题,经过排查与进程的大量IO有关,但是奇怪的是,即使IO已经结束,操作界面时仍然会有卡顿问题。继续排查,发现进程常驻内存的代码段和数据段在大量IO之后变小了,排查过程如下: 为了复现整个过程,使用以下demo代替GUI程序,能得到类似的效果:#include <stdio.h>const int ARRA...原创 2018-07-11 00:29:03 · 1642 阅读 · 0 评论 -
CSAPP第三版运行时打桩Segmentation fault
CSAPP第三版7.13.3节提到了运行时打桩机制,它可以在运行时将程序中对共享库函数的调用进行截获,替换为执行自己的代码。这个机制基于动态链接器的LD_PRELOAD环境变量。如果LD_PRELOAD环境变量被设置为一个共享路径名的列表(以空格或分号分隔),那么当加载和执行一个程序,需要解析未定义的引用时,动态链接器(ld-linux.so)会先搜索LD_PRELOAD库,然后才搜索任何其他的库。原创 2017-08-19 23:53:13 · 2781 阅读 · 13 评论 -
C语言: 结构体的赋值
结构体在 C 程序中使用的较为频繁,能对数据有一定的封装的作用。对一个结构体赋值时,经常采用的方式是,分别对其成员变量赋值。那么能否将一个结构体用赋值号(“=”)直接赋值给另一个结构体呢?网上的答案不一,有说可以的,有说不可以的,有说这样的话两个结构体共用一块内存空间。我们可以从汇编语言的角度来看这个问题,测试程序://test.c#include <stdio.h>int main(){原创 2015-05-09 00:08:13 · 12101 阅读 · 1 评论 -
一个C语言初学者写一个查找替换程序的历程
本人大一,正式接触C语言刚刚三个月原创 2014-05-17 14:09:05 · 2832 阅读 · 0 评论 -
C 语言:指针、free()与 NULL
有时听人说,free 掉一个指针 ptr 之后,ptr 指向的空间会被释放掉,ptr也会被置为 NULL,所以程序中经常会有以下类似语句来判断指针是否指向可用的空间或者:if (!ptr) { //do something} 但是最近在一个实验课中,有一些函数需要首先判断指针 ptr 指向的数据结构是否已经被建立,或者已经被销毁,然后再进行操作。理所应当地使用了上述语句。但程序中却出现了原创 2015-04-09 19:43:48 · 3108 阅读 · 0 评论 -
关于指令、数据、程序和进程的一些思考
从动态链接库说起关于指令和数据的思考实际上是从写一个汇编语言课设开始的,当时要在Windows下写一个截获键盘操作的win32程序,老师推荐了一本《Windows环境下32位汇编语言程序设计》。(实际上这个课设就是这本书上的一个例子) 截获键盘操作就是要靠钩子函数,而使用钩子函数必须使用动态链接库。关于动态链接库,《设计》中有如下叙述: 如果有多个程序用到同一个动态链接库,Windows在物理原创 2015-12-13 19:32:28 · 1837 阅读 · 0 评论 -
glibc 中的 __attribute__ 关键字
今天试着读了glibc的一些源代码,只能用头大来形容我的感受,见到了各种奇怪的标识符,各种宏定义,总之很难通顺的读下去。我决定仔细看看这些奇怪的东西,将出现较频繁的内容大致了解一下。今天我们来看看其中出现次数相当多的“__attribute__”标识符。 举一个我看到的例子:extern void longjmp (struct __jmp_buf_tag __env[1], int __val)原创 2015-12-03 20:52:10 · 2678 阅读 · 0 评论 -
C语言:未包含头文件引起的奇怪错误
转载请注明来源:http://blog.csdn.net/imred/article/details/50756016 历时半年,厚厚的CSAPP终于快要啃完了。但是就在这时,敲书上一个示例代码时却出现一个令人困惑的问题。 出现问题的代码是code/netp/hostinfo.c,代码如下:#include "csapp.h"int main(int argc, char **argv) {原创 2016-02-27 17:04:09 · 2642 阅读 · 0 评论 -
kernel 源码中的 likely() 和 unlikely()
这两个都是宏,展开形式如下:#define likely(x) __builtin_expect(!!(x), 1)#define unlikely(x) __builtin_expect(!!(x), 0)(现在的源代码中可能还加入了ftrace的功能,用于统计预测成功率,改善程序性能,参见ftrace简介) __builtin_expect(!!(x), 1)用来表示程序员预测x值为1的原创 2016-07-24 11:17:05 · 584 阅读 · 0 评论 -
kernel 源码中的 ACCESS_ONCE()
ACCESS_ONCE()也是一个宏,宏定义如下: #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))它还有一堆注释,不仔细看的话会很令人困惑,先放在这里,下面再解释: /* * Prevent the compiler from merging or refetching accesses. The compiler原创 2016-07-26 11:22:28 · 1880 阅读 · 1 评论 -
如何让C语言函数返回一个二维数组
为了让C语言函数返回一个二维数组,有些人这样定义函数:int **foo(int rows, int columns)然后在函数中费劲心机拼出来一个这样的malloc语句:int (*result)[columns] = (int (*)[columns])malloc(rows * columns * sizeof(int));在函数内读写这个数组发现很正常,等把数组返回...原创 2016-09-14 13:55:02 · 16409 阅读 · 2 评论 -
一个极其简陋的C/C++日志工具
总用printf来打日志的话,到后面删除起来太麻烦,所以自己写了几个函数来代替printf。其实也就是把printf包装了一下,然后利用宏根据编译选项是否含有-DDEBUG来判断是否把宏展开为功能代码。代码如下://log.h#ifndef LOG_H_INCLUDED#define LOG_H_INCLUDED#include <stdio.h>#include <string.h>#in原创 2016-11-10 13:03:41 · 1127 阅读 · 0 评论 -
libcurl的使用
简介libcurl是一个客户端URL传输库,支持很多协议(自行查看官方简介:https://curl.haxx.se/libcurl/),简而言之,这个库能爬网页,有了这个库,就不需要自己写socket来爬网页了,方便了很多。 此处使用的语言为C++,虽然libcurl有C++的binding,但是那样就得看两份文档了,太麻烦,况且官方文档提到了在C++下使用时,唯一需要注意的是回调函数不能为非静原创 2016-11-10 15:05:01 · 1442 阅读 · 0 评论 -
C语言:数组和指针的区别
实际上关于数组与指针的区别这个问题在《C专家编程》已经有很详细的阐释,但我想用自己的语言说一说我的理解。数组是指针?最近在做数据结构课设,其中一个函数发生了令人费解的错误,简化后的代码如下:#include <stdio.h>int main(){ char foo[] = "a"; char **bar = &foo; printf("%c\n", *(*bar));原创 2015-05-02 19:08:07 · 27665 阅读 · 14 评论 -
codeblocks使用gtk遇到“undefined reference to:gdk_pixbuf_new_from_file”
一开始我总是以为头文件的问题,但是声明了gdk_pixbuf_new_from_file函数的头文件经过层层包含被包含进来了(所以C预处理器在对源代码进行预处理时并不是一步到位的,还要对替换后代码再替换?),所以并不是头文件没有包含进来。谷歌了一下,dreamincode看到了另一个关于undefined reference to的问题,最后是这样的EDIT:Now I feel st原创 2014-05-31 00:09:47 · 2191 阅读 · 0 评论 -
C语言: 函数调用的开销
初学C语言的时候,我们有时会听说函数调用会有一定的开销,在进行了进一步学习之后,我们来看看原来听说的开销指的什么。 下面是两个非常简单的样例,就不作解释了: 函数调用版本C程序:#include <stdio.h>int sum(int a, int b){ return a + b;}int main(){ int a = 1; int b = 1; in原创 2015-10-02 23:10:54 · 7989 阅读 · 0 评论