记录日常开发中的一些常用技巧,有的可能比较小,不适合专门写一篇文章,那么可以写在笔记总结系列里面。
scp命令用法
发送目录到服务器
比如我想把一个目录下的所有文件发送到服务器中,以C-Thead-Pool为例:
bogon:github coder52$ scp -r C-Thread-Pool/ root@10.211.55.49:~
root@10.211.55.49's password:
LICENSE 100% 1090 592.0KB/s 00:00
thpool.h 100% 4639 3.0MB/s 00:00
funcs.sh 100% 1004 953.8KB/s 00:00
memleaks.sh 100% 1912 2.3MB/s 00:00
api.sh 100% 395 583.6KB/s 00:00
normal_compile.sh 100% 255 337.0KB/s 00:00
heap_stack_garbage.sh 100% 480 559.4KB/s 00:00
README.md 100% 1042 1.3MB/s 00:00
memleak.c 100% 960 1.3MB/s 00:00
optimized_compile.sh 100% 271 395.6KB/s 00:00
wait.sh 100% 1237 1.7MB/s 00:00
threadpool.sh 100% 521 570.4KB/s 00:00
pause_resume.sh 100% 684 650.4KB/s 00:00
pause_resume.c 100% 1041 1.1MB/s 00:00
api.c 100% 1122 1.1MB/s 00:00
nonzero_heap_stack.c 100% 898 1.3MB/s 00:00
conc_increment.c 100% 702 634.8KB/s 00:00
no_work.c 100% 437 567.5KB/s 00:00
wait.c 100% 1089 1.2MB/s 00:00
FAQ.md 100% 2138 1.9MB/s 00:00
Design.md 100% 2169 2.4MB/s 00:00
README.md 100% 4001 4.7MB/s 00:00
example.c 100% 1074 1.3MB/s 00:00
thpool.c 100% 13KB 9.8MB/s 00:00
config 100% 311 409.9KB/s 00:00
pack-f22075098f8ed8b0755df6699af6f077315ca459 100% 21KB 17.7MB/s 00:00
pack-f22075098f8ed8b0755df6699af6f077315ca459 100% 164KB 57.1MB/s 00:00
HEAD 100% 23 20.4KB/s 00:00
exclude 100% 250 264.5KB/s 00:00
HEAD 100% 184 206.5KB/s 00:00
master 100% 184 226.3KB/s 00:00
HEAD 100% 184 163.1KB/s 00:00
description 100% 73 48.3KB/s 00:00
commit-msg.sample 100% 896 1.1MB/s 00:00
pre-rebase.sample 100% 4951 5.4MB/s 00:00
pre-commit.sample 100% 1642 2.2MB/s 00:00
applypatch-msg.sample 100% 478 795.2KB/s 00:00
prepare-commit-msg.sample 100% 1239 1.7MB/s 00:00
post-update.sample 100% 189 309.2KB/s 00:00
pre-applypatch.sample 100% 424 629.3KB/s 00:00
pre-push.sample 100% 1348 2.0MB/s 00:00
update.sample 100% 3611 3.7MB/s 00:00
master 100% 41 53.5KB/s 00:00
HEAD 100% 32 31.4KB/s 00:00
index 100% 2179 1.9MB/s 00:00
packed-refs 100% 183 231.5KB/s 00:00
FETCH_HEAD 100% 204 235.5KB/s 00:00
sourcetreeconfig 100% 372 329.4KB/s 00:00
这样就将Thread-Pool/ 目录下的所有文件发送到了服务器~/Thread-Pool目录下.
拷贝目录到本地
从远程服务器/root目录下,拷贝文件夹C-Thread-Pool到当前服务器/root目录,执行如下命令即可:
[root ~]#scp -r root@10.211.55.49:/root/C-Thread-Pool /root
root@10.211.55.49's password:
输入服务器正确密码即可
gcc参数-D -U
gcc -DDEBUG=1 foo.c
相当于在foo.c中添加了如下语句:
#define DEBUG 1
-D参数我们比较熟悉,可是-U参数却很少用到,-U选项用于删除宏的定义,效果相当于undef,可以使用-U选项来删除预定义宏或之前在命令行方式下用-D选项定义的宏。
函数strtok
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
C语言字符串分割函数strtok,使用之后会更改原字符数组内容,在分隔符结束的地方添加结束字符,返回分隔符开始的地址。
可以使用gdb,查看str内容验证:
13 printf ("%s\n",pch);
(gdb)
string
14 pch = strtok (NULL, " ,.-");
(gdb)
11 while (pch != NULL)
(gdb)
17 printf("After call strtok str = %s\n",str);
(gdb) p str
$1 = "- This\000 a\000sample\000string\000"
(gdb) q
A debugging session is active.
Inferior 1 [process 24120] will be killed.
hosts中添加域名解析
linux中添加域名解析,比如在无法连接外网的环境中添加hosts,可以指向内网指定ip,另一种常用的技巧是添加10.211.55.45 ubuntu,可以直接ssh ubuntu就可以连接到远端服务器。
[root workspace]#cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 parallels-Parallels-Virtual-Platform
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.211.55.45 ubuntu
ssh远程登录服务器
[root workspace]#ssh ubuntu
The authenticity of host 'ubuntu (10.211.55.45)' can't be established.
ECDSA key fingerprint is SHA256:doiViafWwhWy0CLyM1L9tM13ou91FMSC473lrx1lpLY.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'ubuntu' (ECDSA) to the list of known hosts.
root@ubuntu's password:
Last login: Sat Oct 5 18:06:07 2019 from ubuntu-18.04-10.211.55.49.shared
[root ~]#
docker命令
学习极客时间里的教程里遇到如下命令:
docker run -it --rm -v $(mktemp):/etc/resolv.conf feisky/dnsutils bash
其它参数比较熟悉,-v参数是--volume:绑定一个卷,意思是主机中随机的一个文件映射到容器里的/etc/resolv.conf,在容器里修改这个文件,主机里的文件也相应的修改。
min宏实现
如果实现min宏:
#define min(a,b) a<b?a:b
当按照如下方式使用时会存在问题:
int value = -min(2,3)实际调用等价于如下方式
int value = -2<3 ? 2 :3; // Oops.. result will be 2
正确的方式应该:
#define min(a,b) ( (a) < (b) ?(a):(b) )
但是当调用的时候传入的参数比如为i++,不能保证i++执行一次还是两次。
asprintf函数替代snprintf
stackoverflow上有一篇比较好的回答,最近刚定位和解决项目中一个与之类似的问题。
snprintf例子:
#include <stdio.h>
#include <string.h>
int main()
{
char x[5]={0};
int size = snprintf(x,5,"%s%s%s","12","34","56");
printf("%d\n",size);
return 0;
}
gdb查看数组x的内容,可以看到x[4]确实为结束符null.
Breakpoint 1, main () at sprintf.c:5
5 {
(gdb) n
6 char x[5]={0};
(gdb)
8 int size = snprintf(x,5,"%s%s%s","12","34","56");
(gdb)
9 printf("%d\n",size);
(gdb) p x
$1 = "1234"
(gdb) p/x x
$2 = {0x31, 0x32, 0x33, 0x34, 0x0}
(gdb)
sizeof(a++)
sizeof的一个使用问题,示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int a = 10;
size_t size = sizeof(a++);
printf("size:%lu,a:%d\n",size,a);
return 0;
}
程序输出:
[root systemProgramming]#./sizeof
size:4,a:10
原因及解释:
检测竞争条件
维基百科关于竞争条件的解释:
源代码:
simple_race.c
#include <pthread.h>
#include <stdio.h>
int Global;
void *Thread1(void *x) {
Global++;
return NULL;
}
int main() {
pthread_t t[2];
pthread_create(&t[0], NULL, Thread1, NULL);
Global = 100;
pthread_join(t[0], NULL);
}
// compile with gcc -fsanitize=thread -pie -fPIC -ltsan -g simple_race.c
运行结果:
[root systemProgramming]#./a.out
==================
WARNING: ThreadSanitizer: data race (pid=3111)
Write of size 4 at 0x556865a43014 by main thread:
#0 main /root/systemProgramming/simple_race.c:14 (a.out+0xa79)
Previous write of size 4 at 0x556865a43014 by thread T1:
#0 Thread1 /root/systemProgramming/simple_race.c:7 (a.out+0xa0c)
#1 <null> <null> (libtsan.so.0+0x296ad)
Location is global 'Global' of size 4 at 0x556865a43014 (a.out+0x000000201014)
Thread T1 (tid=3113, finished) created by main thread at:
#0 pthread_create <null> (libtsan.so.0+0x2bcee)
#1 main /root/systemProgramming/simple_race.c:13 (a.out+0xa6a)
SUMMARY: ThreadSanitizer: data race /root/systemProgramming/simple_race.c:14 in main
==================
ThreadSanitizer: reported 1 warnings
ThreadSanitizer这个工具来自于Google,目前已集成到clang gcc等,可以用于检测程序中的竞争条件,上面的输出我们可以看到变量Global存在竞争(主线程和线程tid 3113)。
程序中设置断点
在使用gdb调试一些复杂的C程序时,在源代码中添加断点非常实用。
示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int val = 1;
val = 42;
asm("int $3");//set a breakpoint here
val = 7;
return 0;
}
gcc -g -o gdb_ex gdb_ex.c
然后使用gdb调试,运行,可以看到程序自动断到11行。
(gdb) r
Starting program: /root/systemProgramming/gdb_ex
Program received signal SIGTRAP, Trace/breakpoint trap.
main () at gdb.c:11
11 val = 7;
(gdb)
gdb打印内存地址
示例代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main()
{
char bad_string[3] = {'C', 'a', 't'};
printf("%s", bad_string);
return 0;
}
x 0xaddress
x/nfu 0xaddress
Examine the contents of memory.
Examine the contents of memory and specify formatting.
n: number of display items to print
f: specify the format for the output
u: specify the size of the data unit (eg. byte, word, ...)
Example: x/4dw var
我们可以使用这个命令查看内存中的值:
(gdb) b main
Breakpoint 1 at 0x6b2: file bad_str.c, line 6.
(gdb) r
Starting program: /root/systemProgramming/bad_str
Breakpoint 1, main () at bad_str.c:6
6 {
(gdb) n
7 char bad_string[3] = {'C', 'a', 't'};
(gdb)
8 printf("%s", bad_string);
(gdb)
10 return 0;
(gdb) x/16db bad_
bad_key_err bad_string
(gdb) x/16db bad_string
0x7fffffffe3d5: 67 97 116 0 122 -22 -107 -65
0x7fffffffe3dd: -2 98 -31 0 71 85 85 85
(gdb) x/16xb bad_string
0x7fffffffe3d5: 0x43 0x61 0x74 0x00 0x7a 0xea 0x95 0xbf
0x7fffffffe3dd: 0xfe 0x62 0xe1 0x00 0x47 0x55 0x55 0x55
二级指针的理解
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int num = 10;
int i = 0;
char **ptr = malloc(num * sizeof(char *));
char str[10] = {0};
for(i = 0;i < num;i++)
{
ptr[i] = malloc(10 * (i + 1) *sizeof(char));
memset(str,0x0,sizeof(str));
snprintf(str,sizeof(str),"%s_%d","string",i);
memcpy(ptr[i],str,sizeof(str));
}
for(i = 0;i < num;i++)
{
printf("ptr[%d] = %s\n",i,ptr[i]);
free(ptr[i]);
ptr[i] = NULL;
}
free(ptr);
ptr = NULL;
return 0;
}
编译运行结果(使用valgrind检测内存泄露)
[root systemProgramming]#gcc -g -o pointer pointer.c
[root systemProgramming]#valgrind --leak-check=full ./pointer
==31696== Memcheck, a memory error detector
==31696== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31696== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==31696== Command: ./pointer
==31696==
ptr[0] = string_0
ptr[1] = string_1
ptr[2] = string_2
ptr[3] = string_3
ptr[4] = string_4
ptr[5] = string_5
ptr[6] = string_6
ptr[7] = string_7
ptr[8] = string_8
ptr[9] = string_9
==31696==
==31696== HEAP SUMMARY:
==31696== in use at exit: 0 bytes in 0 blocks
==31696== total heap usage: 12 allocs, 12 frees, 1,654 bytes allocated
==31696==
==31696== All heap blocks were freed -- no leaks are possible
==31696==
==31696== For counts of detected and suppressed errors, rerun with: -v
==31696== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
ncat(nc)命令
在Linux.cn看到一篇非常棒的关于ncat命令的文章:10个例子教你学会ncat(nc)命令
valgrind Invalid read/write
valgrind检测内存读写提示非法读写。
源代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
#define MAX_ALLOCS 1000000
int j = 0;
char *ptr[MAX_ALLOCS];
for (j = 0; j < 100; j++) {
ptr[j] = malloc(1024);
if (ptr[j] == NULL)
perror("malloc");
}
for (j = 0; j < 100; j += 1)
free(ptr[j]);
printf("Hello World.\n");
return 0;
}
valgrind 检测运行结果:
[root workspace]#valgrind --leak-check=full ./memory
==10630== Memcheck, a memory error detector
==10630== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10630== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10630== Command: ./memory
==10630==
==10630== Warning: client switching stacks? SP change: 0x1fff000350 --> 0x1ffe85f130
==10630== to suppress, use: --max-stackframe=8000032 or greater
==10630== Invalid write of size 4
==10630== at 0x1087A4: main (memory.c:8)
==10630== Address 0x1ffe85f13c is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid write of size 4
==10630== at 0x1087AE: main (memory.c:11)
==10630== Address 0x1ffe85f13c is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid read of size 4
==10630== at 0x1087FF: main (memory.c:11)
==10630== Address 0x1ffe85f13c is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid write of size 8
==10630== at 0x1087BF: main (memory.c:12)
==10630== Address 0x1ffe85f128 is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid read of size 8
==10630== at 0x4C2FB35: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10630== by 0x1087C3: main (memory.c:12)
==10630== Address 0x1ffe85f128 is on thread 1's stack
==10630== in frame #0, created by malloc (???:)
==10630==
==10630== Invalid read of size 4
==10630== at 0x1087C7: main (memory.c:12)
==10630== Address 0x1ffe85f13c is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid write of size 8
==10630== at 0x1087CF: main (memory.c:12)
==10630== Address 0x1ffe85f140 is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid read of size 4
==10630== at 0x1087D7: main (memory.c:13)
==10630== Address 0x1ffe85f13c is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid read of size 8
==10630== at 0x1087DF: main (memory.c:13)
==10630== Address 0x1ffe85f140 is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid read of size 4
==10630== at 0x1087F8: main (memory.c:11)
==10630== Address 0x1ffe85f13c is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid write of size 4
==10630== at 0x108808: main (memory.c:17)
==10630== Address 0x1ffe85f13c is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid read of size 4
==10630== at 0x108833: main (memory.c:17)
==10630== Address 0x1ffe85f13c is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid read of size 4
==10630== at 0x108814: main (memory.c:18)
==10630== Address 0x1ffe85f13c is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid read of size 8
==10630== at 0x10881C: main (memory.c:18)
==10630== Address 0x1ffe85f140 is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
==10630== Invalid read of size 4
==10630== at 0x10882C: main (memory.c:17)
==10630== Address 0x1ffe85f13c is on thread 1's stack
==10630== in frame #0, created by main (memory.c:6)
==10630==
Hello World.
==10630== Warning: client switching stacks? SP change: 0x1ffe85f130 --> 0x1fff000350
==10630== to suppress, use: --max-stackframe=8000032 or greater
==10630==
==10630== HEAP SUMMARY:
==10630== in use at exit: 0 bytes in 0 blocks
==10630== total heap usage: 101 allocs, 101 frees, 103,424 bytes allocated
==10630==
==10630== All heap blocks were freed -- no leaks are possible
==10630==
==10630== For counts of detected and suppressed errors, rerun with: -v
==10630== ERROR SUMMARY: 1207 errors from 15 contexts (suppressed: 0 from 0)
[root workspace]#
如果修改MAX_ALLOCS的值从1000000修改为100000,valgrind将不会报错。