2007-12-31 17:12:00 rongjianxing 阅读数 1537

c++代码在windows,aix,linux上的移植

 

容健行@2007-12-21

 

 

转载请注明

源文出处:http://www.devdiv.net/home/space-125-do-blog-id-363.html

我目前工作中的大多数项目是在aix上跑的,最近有个aixc++项目要移植到linux上,而我个人喜欢使用VC作为开发工具。因为这样,需要对项目windowsaixlinux上的移植,在这个过程中作了些总结。

现假设平台与编译工具对应如下:

windows――vc

aix――xlc

linux――gcc

 

目录:

1.    c++标准

1.1.     变量、函数重定义

1.1.1.      避免在头文件里定义变量。

1.1.2.      避免在头文件里定义外部函数

1.2.     函数返回值

1.3.     模板

1.3.1.      派生类如果使用基类的函数或成员变量,应该在前面加“this->”,或在类声明中加入“using 基类函数;”

1.3.2.      使用了基类或其它模板类里定义的类型,要在类型前加typename

1.4.     标准与现实之间

2.    操作系统

2.1.     API

2.2.     硬件 32位 64

3.    编译器对语言的扩展

3.1.     编译器命令与选项

3.2.     函数的调用约定:

3.3.     dll函数符号导出

3.4.     宽字符

4.    Unicode,使用icu

5.    封装

5.1.1.      ACE

5.1.2.      QT

 

1.   c++标准

c++的发展已经有几十年历史了,但标准是在1998年制定的,在标准之前,出现了很多编译器,各个编译器对于语法上存在一定差异。

vcxlc这种是属于企业级应用的工具,会追求向前兼容。以保证以前的代码能够使用,所以如果有不怎么标准的代码,编译器也会让它通过。而gcc比较偏向于研究应用的工具,会追求标准化。

这就产生了有些代码在vcxlc上通过,而在gcc上编不过的情况。

1.1.   变量、函数重定义

1.1.1.      避免在头文件里定义变量。

假设a.h定义了一个变量int error

b.cpp#include “a.h”

c.cpp#include “a.h”

则在同一个程序中,error定义了两次,编译器在链接的时候报错。

1.1.2.      避免在头文件里定义外部函数

函数的道理其实跟变量差不多,也会出现重定义。但如果一定要把函数写在头文件可以有三种方法:

加上inline

加上static

使用一个空的名字空间把函数包起来。

 

变量其实也可以用static或空名字空间来解决重定义的问题,但变量的问题比函数复杂,在头文件里使用了全局变量不但带来编译的问题,还会容易引入潜在错误,如果要使用多线程,则使到问题越发复杂。

如果一定要使用全局变量有一个比较好的方法,定义一个全局函数,函数是定义一个静态变量,函数返回该变量的一个引用,事例如下:

// a.h

int& theError();

 

// a.cpp

int& theError()

{

     static int    s_error;

return s_error;

}

哪个地方要使用error这个全局变量的话,#include”a.h”后直接用theError()就好了。比如你可以这样用:

theError() = -1;

 

另外,也不建议在头文件中引入名字空间。如果在头文件中using namespace std,使用字符串组件用“string”的名字就可以了,但在stl标准化之前(甚至之后),大量的字符串组件存在,别人也可能使用“string”这个名字。一不小心就冲突了。

1.2.   函数返回值

c语言以及c++98标准制定之前的c++,函数声明或定义如果没有返回值,则隐式定义为返回int。但c++98标准之后,规定函数必须制定返回值。

对于类似于以下的代码:

fun(int, char);

早期的gcc,以及目前的大多数编译器都可以通过,但比较新版的gcc是会报错的。

1.3.   模板

*注:以下属于编译器细节,如果不想了解或看完后还是不了解的话,可以略过:

c++标准制定前,模板相当于宏,在用到模板的地方会根据模板参数直接把模板代码翻译为非模板的代码。

如果事情是这样先翻译后编译的话,模板在各个编译器上应该是差不多的了。但c++委员会为了使到模板的错误信息(即在写模板的时候就把代码写错了)更加易于理解,以及为了在解析模板的阶段检查潜在的隐患,规定模板的查找分为两个阶段,第一阶段在看到模板的定义时,第二阶段是模板实例化时。并且标准规定“对于模板中的非依赖型名称,将会在看到的第一时间进行查找”。有了这个概念后,让我们考虑下面的例子

template<typename T>

class DD : public Base<T>

{

public:

     void f() { basefield = 0; } // (1) 代码有问题,标准c++会在第一阶段查找时给出错误。

};

 

template<>

class Base<bool>

{

public:

     enum { basefield = 42; }

};

 

void g(DD<bool>& d) {  d.f(); }

 

如果你不想在第一阶段就进行查找,那么可以在basefield前加上this->Base<T>::Base<T>::basefield的名字是依赖型的(第一阶段时,T还没定义,basefield具体是什么,依赖于T,直到实例化时才可以知道T是什么)C++标准规定“对于依赖型的名字,会推迟到实例化的时候查找”。查找推迟后,错误是还有,不过具体错误已经清晰定位了。

c++模板的确是个挺复杂的东东,就算你不写模板代码,也免不了要跟模板打交道,比如使用stl。编写或使用模板时要注意一些规则:

1.3.1.      派生类如果使用基类的函数或成员变量,应该在前面加“this->”,或在类声明中加入“using 基类函数;

比如:

template<typename CharType>

class CMyString : public std::basic_string<CharType>

{

public:

     size_t Length()

     {

         return this->length(); // 这里会调用std::basic_string<CharType>::length()函数。

     }

};

template<typename CharType>

class CMyString : public std::basic_string<CharType>

{

     using std::basic_string<CharType>::length;     // 声明使用基类的length函数。

public:

     size_t Length()

     {

         // 有了std::basic_string<CharType>::length的声明,length()就会成为依赖型(依赖于CharType),直到实例化时才查找该函数的具体地址,如果没有using length的声明,length()会作为一个非依赖型名字,编译器会在全局函数里查找,如果找不到,则报错,如果找到,则调用全局函数length()

         return length(); // 这里会调用std::basic_string<CharType>::length()函数。

     }

};

1.3.2.      使用了基类或其它模板类里定义的类型,要在类型前加typename

比如:

template<typename CharType> inline

void Fun(std::basic_string<CharType>& str)

{

     // std::basic_string<CharType>::iterator 是一个名字,

     // 且该名字依赖于模板类std::basic_string的参数CharType

     // CharType还没确定时,iterator有可能是一个类型名,也有可能是静态变量名,或是一个枚举名。

     // 加上typename后,指明std::basic_string<CharType>::iterator是一个类型名。

     typename std::basic_string<CharType>::iterator it = str.begin();

}

 

1.4.   标准与现实之间

当然,对于以上这些标准vcxlc执行得不是太严格,不按照上面这样用也可以通过,但gcc是严格按照标准办事的。如果代码想要有比较强的移植性以及健壮性的话,我们自己还是按照标准写为好。

2.   操作系统

2.1.   API

这个大家应该会比较清楚。

写程序免不了要使用操作系统的功能,windowslinuxunix定义了不同的API用来访问操作系统。

如果程序必须操作系统的特定功能的话,那就没得说了(不过这样的程序在设计之初就没打算过要跨平台)

如果程序使用的是一些操作系统的公共功能的话,那么使用以下形式的代码

#ifdef   WIN32

     调用windowsAPI

#else ifdef   LINUX

     调用linuxAPI

#else

     调用XXX系统的API

#endif

编译的时候,只需要把相关平台上加上这些宏就会自动调用自身平台的API了。

2.2.   硬件 32位 64

目前windows的硬件是以32位的intel处理器为主,而大多数unix64位的专用处理器。

对于long以及指针类型来说,在windows平台是32位,而在aix可能就是64位了。VC是使用__int64来作为64位类型的,windows上还大量使用了一个叫LARGEINT的结构体来作为64位变量的储存:

typedef struct _LARGEINT

{

  ULONG LowLong;

  LONG HighLong;

} LARGEINT;

typedef LARGE_INTEGER *LPLARGEINT;

3.   编译器对语言的扩展

3.1.   编译器命令与选项

因为本文主要讨论代码的可移植性方面的,由于各编译器命令和选项繁多,不一一列出了。

3.2.   函数的调用约定:

调用约定

语义

cdecl

从右到左地将被调用函数的参数压入堆栈。在执行完毕之后,由调用函数将参数弹出堆栈。

stdcall

从右到左地将被调用函数的参数压入堆栈。在执行完毕之后,由调用函数将参数弹出堆栈。

fastca

将最前面的两个参数传递到 ECX EDX 寄存器中,同时将所有其他参数从右到左地压入堆栈。由被调用函数负责清除执行后的堆栈。

为了支持这些函数属性,比如stdcallVC中是在函数前加 __stdcall”或“_stdcall,而gcc是函数前加“__attribute__((stdcall))”。xlc是两种方法都支持。

 

3.3.   dll函数符号导出

VC使用“__declspec(dllexport)”导出函数符号,使用“__declspec(dllimport)”导入。但为了得到纯C(名字完全没有修改过)函数,建议使用.def文件导出。

gcc使用__attribute__ ((visibility("hidden")))声明为不导出,使用((visibility("default")))声明为导出。如果没有声明,则默认为导出。但因为大多数函数是不导出的,建议在编译时加上-fvisibility=hidden选项,这样,只有没有做声明或声明为hidden的都不导出,这样可以加快dll的加载速度。

xlc也是默认为导出。

3.4.   宽字符

c++为宽字符制定了标准类型wchar_t,但有些编译器是以扩展的形式提供该类型的。比如VC,你要#include<wchar.h>才能使用wchar_t,而gcc是把wchar_t作为内建类型。

注意,VC提供了选项是否把wchar_t作为内建类型,但使用它之前,最好你的工程中用到的其它静态库都是使用该选项的,要不然就会链接不过。

 

4.   Unicode,使用icu

关于unicode本身就是一个很复杂的问题,这里不作专门讨论了。

c++代码的字符类型分为单字节和宽字节,经常需要做字符编码间的转换。之前做一个xml读写的项目,需要utf16gb2312格式间的互转,但系统自带的函数和xerser-c带的函数在windows上是可以正常工作的,在aix上却不可以转换中文字符。找了些资料,IBMicu(International Component for Unicode)组件可以解决这个问题。

下载icu-4代码,编译后得到icuuc库组件和一个叫“include”的目录(里面是头文件)。把包含路径设到它的“include”,以及链接icuuc后,以下代码可以在多个平台上实现utf16gb2312的转换。

// XMLString自带的转换函数在aix上不能把utf16转成gb2312

// 改为使用icu的转换函数。

// {{

#ifndef UCNV_H

#include "unicode/ucnv.h"

#endif

 

inline

char* UTF16_to_gb2312(const wchar_t* strtranscode, size_type len)

{

     const size_type sizeDest = (len + 1) * 2;

     char* pResult = new char[sizeDest];

 

     UErrorCode status = U_ZERO_ERROR;

     UConverter *conv = ucnv_open("gb2312", &status);

     assert(U_SUCCESS(status));

 

     ucnv_fromUChars(conv,

         pResult, sizeDest,

         (const UChar*)strtranscode, len,

         &status);

 

     ucnv_close(conv);

 

     return pResult;

}

 

inline

wchar_t* gb2312_to_UTF16(const char* strtranscode, size_type len)

{

     const size_type sizeDest = (len + 1);

     wchar_t* pResult = new wchar_t[sizeDest];

 

     UErrorCode status = U_ZERO_ERROR;

     UConverter *conv = ucnv_open("gb2312", &status);

     assert(U_SUCCESS(status));

 

     ucnv_toUChars(conv,

         (UChar*)pResult, sizeDest,

         strtranscode, len,

         &status);

 

     ucnv_close(conv);

 

     return pResult;

}

// }}

5.   封装

对于编写跨平台的代码当然好,但为了跨平台,少不了”#ifdef WIN32”之类的代码,这种代码一但多了,会很影响阅读的。应该把这些公共功能包装起来,提供一个可以被多个平台访问的接口,特别是对于API的封装。

5.1.1.      ACE

现在有很多开源的类库有API的封装,比如ACE等。但只是实现了轻量级的封装,大概是线程、进程、互斥体、锁等。ACE虽然是对系统作了个轻量级封装,但其本身却是一个重量级的库。

5.1.2.      QT

API中最复杂的是窗体和图形设备相关的,Windows的窗体和图形设备API加起至少有几千个。实现这些封装可以称得上是重量级的了,比如QT,但QT是一种比较特殊的开源,不给钱而使用它开发营利性软件会引起连锁性的法律问题。

Kylix(delphilinux)上所使用的支持跨平台的CLX组件库就是基于QT的。Kylix支持pascalc++。不过用c++就比较转折了,先是用c++调用pascal写的VCL,再用VCL调用c++写的CLXCLX再调用QT。如果刚好你程序在这段出现问题想调试一下代码,就头大了。(有空打算一篇写关于跨语言的文章)

 

2014-04-19 00:59:08 pianzif 阅读数 5307

在aix上装个bash就可以了

就是  shell 编写好了 到aix下改下不就好了  思想和流程最重要


理念是相通的


不管那么多,先学好学精一个再说


在我看来,AIX和Linux差别不大,都是开放平台的OS,平时管理员在这些平台上做的工作也大致相同,OS无非就是资源管理、安全配置,性能调优什么的。掌握了思路,剩下的就是一些具体产品设计以及命令使用上的小小区别。

AIX也是UNIX的一种。UNIX 和LINUX也是从同一个根发展出来的。时间长了,有各自的演生产品。大致原理都一样。其实学习UNIX就是学习它的原理与架构。


现在转学AIX也不是一定也要把linux扔了,其实他们没有特别大的区别。主要的构造都一样的。
也就是AIX为了需要才出现一些新的功能适应服务器的发展需要。


其实他们的OS基本上是相通的,有区别主要是一些系统管理工具或一些参数,所以你没有必要为这个而去想太多。。


基本差别不大,重要的是思想。


------

AIX全名为(Advanced Interactive Executive),它是IBM公司的UNIX操作系统。

虽然Linuxaix都是Unix兼容的操作系统,但他们在不同的领域存在各自的特点和差异

而且都说aix在操作是比较方便的,我感觉和linux差不多,当然可能是我对AIX还不熟;下面是我总结的一些差异:

1Linux是一个开放的系统,可以运行在大多数硬件环境中;aix属于专用系统,必须运行于专有硬件平台之上;所以最大的差别是支持的硬件平台不一样,Linux是在X86上跑的,AIX是专门为IBM自己的power架构开发的

 

2AIX是商业版本UNIX,是付费产品,除了原有的systemV架构的UNIX基础指令外还开发了自身的管理指令;而linuxsystemV架构的unix的简化版本,是开放源码的,所有指令的源码你都可以看到使用修改,也可以免费为他提供自己开发的指令

 

 

3在基本命令方面用法都差不多也大部分一样,但也存在这差异;例如

查看IP地址及VLAN信息

AIX: ifconfig -alsdev -Cc adapaterlsattr -El ent8

Linux: ifconfig和 ip addr

有些aix 上有的命令在linux 上没有这些命令基本上和filesytem, lvm 相关的

例如:
          lsdev ,lspv, lsvg, lslv ,lsfs...
          chdev, chpv,chvg,...

4LVM层面的命令有点不同,既磁盘管理。linux 先创建物理卷PV,再创建卷组VG,再创建LV和文件系统。同样AIX也是这样。在命令上面区别:aix  createvg       linux: vgcreate  

5、在文件系统上:AIX可以直接去创建文件系统,而且不需要去编辑fstab文件。AIX中你可以使用smitty菜单执行命令 smitty vg   smitty mklv smitty fs等等,进去后就可以找到相应对VGLV、文件系统操作的命令。另外AIX中的PV是直接被系统认到的磁盘:hdisk。可以根据需要,挂很多硬盘。vg 可以放在很多hdisk 上。而linux就需要先去创建pv。这样看来AIXfilesystem方面安全性、容量方面比linux要强些。

    

 

以上是我在操作AIX和对AIX了解后所写的,当然还有很多区别我这里就不是太清楚了,还需要以后的积累和总结。



2018-07-18 09:12:48 zfb19860716 阅读数 2357

                                              AIX 挂载linux下的nfs

       今天客户有需要,对AIX小机中的一套oracle RAC数据库迁移到另一套AIX 的oracle RAC数据库下,但是两套小机都没有额外的空间来存储备份数据,这时就想到了NFS,可是以前只有linux的NFS使用经验,怎么办呢~~~在网上随便找了个文章看了下,感觉和linux下的方式差不多。

  搭建linux NFS服务器

     安装nfs包
       rpm -ivh nfs-util
       rpm -ivh nfs-util-lib
     修改exports配置文件
       vi  /etc/exports
       /mnt/ntfs 192.98.100.0/24(rw,sync,no_root_squash)
    启动NFS服务
       service nfs restart

  客户端挂载

开始直接使用的没有参数的挂载方式
mount xxx.xx.xx.xxx:/expbak /expbak
当在执行EXPDP的时候会报错,提示权限不足或者其他什么错误的
后来使用metlink账号,看到有同僚遇到过类似问题,随后复制mount参数重新挂载
mount -F nfs -o 
rw,bg,hard,nointr,rsize=32768,wsize=32768,proto=tcp,noac,forcedirectio,vers=3,suid 
xxx.x.x.x:/expbak /expbak

以下是挂载RAC和非RAC的参数

For RAC:

rw,bg,hard,nointr,rsize=32768,wsize=32768,proto=tcp,noac,forcedirectio,

vers=3,suid

and non-RAC: rw,bg,hard,rsize=32768,wsize=32768,vers=3,[forcedirectio or

llock],nointr,proto=tcp,suid

~> mount -o

rw,bg,hard,rsize=32768,wsize=32768,vers=3,forcedirectio,nointr,proto=tcp,suid

创建导出的目录

在mount的目录下使用oracle用户创建EXPDP导出的目录
su - oracle
mkdir -p /expbak/expbak
在linux服务端也要创建oracle与相应的组
groupadd oinstall
groupadd dba   
useradd -g oinstall -G dba oracle   
passwd oracle

oracle用户执行EXPDP导出

创建系统目录
mkdir -p /expbak/expbak
数据库创建导出目录
create or replace directory ORADUMP as '/expbak/expbak';
数据库删除目录
drop directory oradump;
查看创建的目录
select  * from dba_directories;
授权给用户
grant read,write on directory ORADUMP to system;
后台执行导出的命令
nohup expdp system/xxx schemas=xxx,xxx directory=ORADUMP dumpfile=xxx.dmp
logfile=xxx.log cluster=no  EXCLUDE=TABLE:\"IN\(\'tt\'\)\"  compression=all parallel=4 &

 

2009-06-30 11:14:00 gobitan 阅读数 0

LinuxAIX使用差异记录

        从今年三月份以来,每天的工作平台同时涉及AIXLinux,经常遇到一些它们之间使用的一些差异,平时记录下来,已备查用。

 

1. 查看IP地址及VLAN信息

AIX: ifconfig -a,lsdev -Cc adapater和lsattr -El ent8

Linux: ifconfig和 ip addr

 

2. 通过端口号找到对应的运行程序

AIX: 未知

Linux: netstat -apvn|grep 8080 

[root@app1 ~]# netstat -apvn|grep 1099
tcp        0      0 0.0.0.0:1099                0.0.0.0:*                   LISTEN      20322/rmiregistry  
tcp        0      0 192.168.48.1:1099           192.168.48.1:42839          ESTABLISHED 20322/rmiregistry  
tcp        0      0 192.168.48.1:49566          192.168.48.1:1099           ESTABLISHED 25721/java         
tcp        0      0 192.168.48.1:1099           192.168.48.1:49566          ESTABLISHED 20322/rmiregistry  
tcp        0      0 192.168.48.1:42839          192.168.48.1:1099           ESTABLISHED 21599/java         
tcp        0      0 192.168.48.1:42745          192.168.48.1:1099           ESTABLISHED 20396/java         
tcp        0      0 192.168.48.1:1099           192.168.48.1:42745          ESTABLISHED 20322/rmiregistry

 

[root@app1 ~]# ps -ef|grep 21599
namp     21599     1  0 Aug12 ?        01:09:52 /usr/java/jre1.6.0_12/bin/java -Dis_cluster=true -Ddyn_parameter_file=/opt/nawg/config/dyn_parameter.cfg -Dwap1.traffic.ifname=192.168.48.1 -Dwap2.traffic.ifname=192.168.48.1 -Dradius.traffic.ifname=192.168.48.1 -Dpush.traffic.ifname=192.168.48.1 -Dnbg.jndi.ifname=192.168.48.1 -Dis_cluster=true -Ddyn_parameter_file=/opt/nawg/config/dyn_parameter.cfg -Dwap1.traffic.ifname=192.168.48.1 -Dwap2.traffic.ifname=192.168.48.1 -Dradius.traffic.ifname=192.168.48.1 -Dpush.traffic.ifname=192.168.48.1 -Dnbg.jndi.ifname=192.168.48.1 -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file=/opt/tomcat/conf/logging.properties -Djava.endorsed.dirs=/opt/tomcat/endorsed -classpath :/opt/tomcat/bin/bootstrap.jar:/opt/tomcat/bin/commons-logging-api.jar -Dcatalina.base=/opt/tomcat -Dcatalina.home=/opt/tomcat -Djava.io.tmpdir=/opt/tomcat/temp org.apache.catalina.startup.Bootstrap start

 

   

       

 

2009-03-31 16:40:29 congao1735 阅读数 61
首先说一下大致情况,就是目前生产环境(AIX server)上边有一数据库 product,现在想迁移到本地做一下测试环境,由于本地服务器只是linux server所以,不可以直接的用backup 和restore恢复。需要用db2look和db2move配合一下来实现迁移过程,本操作适用于各类操作系统之间的迁移。
 
  首先这些在Aix服务器上做
 
  1. 用db2look把aix上的product数据库的DDL语句导出来。
 
  db2look -d product-a -e -o product.sql
 
  输出结果是:
 
  aix:/home/db2inst1$ db2look -d product-a -e -o product.sql
 
  —— Generate statistics for all creators
 
  —— Creating DDL for table(s)
 
  —— Output is sent to file: product.sql
 
  2.用db2move 命令导出ixf和msg文件
 
  db2move pdm export
 
  屏幕输出类似如下信息
 
  ***** DB2MOVE *****
 
  Action: EXPORT
 
  Start time: Tue Mar 11 01:26:43 2008
 
  Connecting to database PRODUCT…… successful! Server: DB2 Common Server V8.2.1
 
  EXPORT: 4 rows from table "PROCORE "."PLAN_MASTER"
 
  EXPORT: 3 rows from table "PROCORE "."PERIOD_MASTER"
 
  EXPORT: 3849 rows from table "PROCORE "."PLAN_OBJ"
 
  EXPORT: 26176 rows from table "PROCORE "."REGION"
 
  EXPORT: 340 rows from table "PROCORE "."CTY_MASTER"
 
  系统执行完之后会生成一堆。ixf 和。msg文件
 
  3. 在本机或目标机(linux) 上建立一个目录如product,product.sql和上步产生的文件都ftp过来。
 
  ftp servername
 
  bin
 
  prompt off
 
  mget *
 
  close
 
  quit
 
  即可
 
  4.在本地新建一数据库可以原aix数据库同名如product
 
  CREATE DATABASE "PRODUCT"
 
  ON '/home/db2inst1/'
 
  ALIAS "PRODUCT"
 
  USING CODESET ISO8859-1
 
  TERRITORY US
 
  COLLATE USING Compatibility
 
  NUMSEGS 1
 
  DFT_EXTENT_SZ 32;
 
  5. 建立本数据库的所有表,用第一步生成的DDL语句来生成
 
  db2 –vtf product.sql
 
  6. 最后一步,导入所有数据
 
  db2move product import
 
  注意:此命令要在第三小download下来的那些文件(*.ixf *.msg)所在的目录中执行
 
  测试一下db2 connect to product;
 
  如果看到成功信息,db2数据库从aix迁移到linux上边就成功了。
 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/15082138/viewspace-582455/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/15082138/viewspace-582455/

AIX和linux SSH互信

阅读数 269