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就可以看到一大串的列表了,还有提交时间。