周末在家收拾东西,找到一本刚入职时记的笔记,重新读一遍记录部分内容方便查阅。

获取下标为n的元素地址

当时记录在笔记本上旁边有个大大的问号,为何不使用下标形式呢?

#include <stdio.h>
//获取下标为n的元素地址
#define ELEM_PTR(base,n,esize) ((void *)(((char *)base + n*esize)))

int main()
{
    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    printf("address of fifth elem = %p.\n",ELEM_PTR(arr,5,4));
    printf("fifth elem = %d.\n",*(int *)ELEM_PTR(arr,5,4));

    return 0;
}

运行结果:

[root c++]#./a.out
address of fifth elem = 0x7ffc45463124.
fifth elem = 6.

查看linux系统是32位 64位

使用命令lscpu可以看到系统架构 x86_64,小端方式 双核 6代等信息。

[root c++]#lscpu
Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              2
On-line CPU(s) list: 0,1
Thread(s) per core:  1
Core(s) per socket:  2
Socket(s):           1
NUMA node(s):        1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               61
Model name:          Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz
Stepping:            4
CPU MHz:             2700.000
BogoMIPS:            5400.00
Hypervisor vendor:   KVM
Virtualization type: full
L1d cache:           32K
L1i cache:           32K
L2 cache:            256K
L3 cache:            3072K
NUMA node0 CPU(s):   0,1
Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx rdtscp lm constant_tsc nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single pti fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap xsaveopt dtherm arat pln pts

编程中使用宏的方式:

// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif

// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif

确定linux库文件时32位 64位

确定静态库动态库位数的方法:

objdump -a example.a / example.so

示例:

[root c++]#objdump -a /var/lib/parallels-tools/GL/libglx.so

/var/lib/parallels-tools/GL/libglx.so:     file format elf64-x86-64
/var/lib/parallels-tools/GL/libglx.so

查看so中是否存在某函数

nm xxx.so | grep func_name
T:存在函数

unrandom.c

int rand(){
    return 42; //the most random number in the universe
}

使用如下命令将其编译成动态库:

gcc -shared -fPIC unrandom.c -o unrandom.so

使用方法:

[root c++]#nm unrandom.so | grep rand
000000000000057a T rand
[root c++]#
[root c++]#
[root c++]#nm unrandom.so | grep random

LD_PRELOAD用法

笔记里有一处记录hook的方法,比如定位问题时想看下进程是被哪个进程杀掉,这里可以hook kill,记录kill调用关系,一种场景是允许你重新编译代码替换到环境中,但绝大部分客户环境场景是不能随意替换二进制文件。一种可行的方法:Linux下LD_PRELOAD的简单用法。这边笔记算我整个博客里实用的文章top 5了。

linux tar命令

压缩:
tar zxvf xxx.tgz XXX/

解压
tar zxvf xxx.tgz

解压到某个文件
tar zxvf library.tgz -C /root/example

gdb中使用shell

在调试问题时如果已经使用gdb attach到线程里,又想使用命令查看某些信息,在不重新打开一个窗口的情况下,可以使用shell cmd执行。

lsmod命令用于显示已经加载到内核中的模块的状态信息
lsmod | grep -i ext3 (grep -i忽略大小写)

grep -o作用

周五解决了一个关于grep的bug,查看代码提交记录发现居然是2018年同一个实习生写的代码,巧的是上次那个问题也是我花了一天时间从一个2000多行的脚本中定位到了原因。
man grep 查看-o选项:

-o, --only-matching
Print only the matched (non-empty) parts of a matching line, with  each such part on a separate output line.

我们来实际看一个例子:

[root ~]#cat file
foo foo
main
example
foo
[root ~]#
[root ~]#grep -o foo file
foo
foo
foo
[root ~]#
[root ~]#
[root ~]#grep foo file
foo foo
foo

如果要统计出现过foo的行数,是千万不能加-o,加了会导致统计的行数比实际行数多导致后续逻辑出错。当然如果要统计foo出现的次数是需要加-o然后统计行数就是foo出现的次数。
脚本一旦超过500行我认为就需要将脚本拆分成不同文件,一个2000多行的脚本是非常不利于维护。

return和exit的区别

What is the difference between exit and return?