Linux下用g++编译共享库的一个问题
最近在使用linux下的共享库so的时候遇到一个奇怪的问题,做个记录,方便备查。
一般来说,如果用gcc编译的时候加上-shared和-fPIC选项,可以把源文件编译成一个so文件,可以在其他源程序连接阶段把这个链接上去,从而可以调用so文件提供的函数接口,这样可以多文件共用一个so文件提供的函数,即节省内存空间,也便于更新,所有的接口只需要更新so文件就行。
其实除了上面的方法,还有一个方法,那就是在运行时由程序自己动态加载so文件,使用一系列系统调用如dlopen,dlsym,dlclose等来进行动态加载,获取函数地址从而进行函数调用,关闭加载的so文件等。
一般以第一种方法用得多,但是第二种方法更灵活,结合配置文件,更具一般意义上的服务扩展性。 但是就是在用第二种方法的时候出现了一点问题。
这里把问题抽象一下,假设有一个源文件是要编译为so文件的,假设这个源文件只提供一个简单的函数,add,取两个整数为参数,返回它们的和,源文件为add.c,代码如下:
#include <stdio.h> int add(int a, int b) { return a+b; }
gcc -shared -fPIC add.c -o libadd.so
#include <stdio.h> #include <stdlib.h> #include <dlfcn.h> int main(int argc, char *argv[]) { void * handle; int (*func)(int, int); char *error; handle = dlopen("libadd.so", RTLD_LAZY); if(!handle) { fprintf(stderr, "%s\n", dlerror()); exit(1); } func = (int (*)(int,int))dlsym(handle, "add"); if((error = dlerror()) != NULL) { fprintf(stderr, "%s\n", error); exit(1); } func(3, 4); dlclose(handle); return 0; }
gcc test.c -o test -ldl
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
./libadd.so: undefined symbol: add
$ nm libadd.so |grep add
00000000000005ec T _Z3addii
$ c++filt _Z3addii
add(int, int)
extern "C" { // the function code ... }
$ nm libadd.so |grep add
00000000000005dc T add
15身份证号码转18位的程序
以前在哪看到的,安全焦点吧!丢这做个备份
/*输入原来的15位身份证号码,产生新的18位身份证号码的程序*/ #include "stdio.h" #include "string.h" #include "conio.h" /* * gen New 18 ID Card from old 15 ID */ char genNewID( char ID[], char NewID[]) { int W[18] = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2,1}; char A[11] = {'1','0','x','9','8','7','6','5','4','3','2'}; int i,j,S; if(strlen(ID) != 15) return -1; memcpy( NewID, ID, 6 ); NewID[6]='1'; NewID[7]='9'; NewID[8]=0; strcat( NewID, &ID[6] ); S = 0; for(i=0;i<17;i++) { j = (NewID[i] - '0') * W[i]; S = S + j; } S = S % 11; NewID[17] = A[S]; NewID[18] = 0; return A[S]; } int main(int argc, char* argv[]) { char ID[20], NewID[20], ret; puts("输入原来的15位身份证号码,产生新的18位身份证号码\n"); do{ printf("Input your old 15 ID Card: "); scanf( "%s", ID ); if(stricmp(ID, "exit") == 0)break; ret = genNewID( ID, NewID ); printf("Your New 18 ID Card: %s \n", ret != -1 ? NewID : "Input Error!!"); }while(1); getch(); return 0; }
测试堆的最大申请数量
看到说linux下的虚拟地址空间分给进程本身的是3GB(高址的1GB是内核空间,也就是0xc000000以上地址),所以有这样一个程序来测试用malloc最多能申请多少内存?
#include<stdio.h> #include unsigned max=0; int main(void) { int i,count; unsigned size[]={1024*1024,1024,1}; for(i=0;i<3;i++){ for(count=1;;count++){ void *p=malloc(max+count*size[i]); if(p){ max+=count*size[i]; free(p); } else{ break; } } } printf("The max memory i can alloc is %u\n",max); return 0; }
在我的linux机器上跑了后发现只有1.1G左右的空间,想一下应该是内存768M+swap400多M,所以到不了那么大吧!
求三个参数中最大两个的平方和
看到一题,实现一个函数,求三个函数中最大的两个参数的平方和。
很自然的,想到这样的方法:
if(y > x && z > x){
return y * y + z * z;
}
if(x > y && z > y){
return x * x + z * z;
}
if(x > z && y > z){
return x * x + y * y;
}
}
if (x <= y && x <= z){
return y * y + z * z;
}
return sum_square_largest(y, z, x);
}
分享代码的好地方
介绍一个分享以及在线运行代码的好地方,codepad,在线运行支持语言种类也很多,当然那个PlainText就免谈了(其实是分享用)。
Language:
界面很简洁,一看就知道怎么用,注意到下面那个Private选项了吗?这里其实可以分享代码,是个geek的好地方,有的人甚至写出了VIM上 用的插件,可以直接在vim里面写代码,然后发布到这里来分享。
程序员用的东西一向以简洁高效著称,这里的注册就很简单,只要你打个用户名和密码就成,密码也让你只打一遍,请保证正确,不过geek一般都自信不会打错。
想看最近都有哪些代码提交,点击那个Recent Pastes就可以看到一大串的列表了,还有提交时间。