大型C工程中存在模块与模块之间传递结构体的编译一致性问题,因为C是静态语言,编译后结构体成员都固化为地址偏移量,当结构体定义变动后必须保证相关模块全编译,否则会破坏进程栈且程序无法主动发现。
InterBankPlus交易管理层精心设计了动态结构DS机制,解决了全编译问题,并做了大量使用细节封装,使得使用尽可能方便。
调用者模块先DS_NEW一个动态结构DS,DS_ADD输入变量、变量类型、值,然后调用被调用者模块入口函数,被调用者模块从动态结构中DS_GET出变量,处理后DS_SET回动态结构,返回调用者模块,调用者模块DS_GET输出变量,最后DS_DELETE动态结构。
模块内部还是建议使用静态结构体,因为内部一般都是编译一致的。
通过动态结构DS机制,模块之间可以安全的传递数据,至多也可被程序主动发现报错,不至于被动的造成进程异常。
小技术解决大问题。
#include "ibtm_in.h"
struct DS_infunc
{
char ch ;
short s ;
int i ;
long l ;
float f ;
double d ;
char buf[ 64 + 1 ] ;
} ;
int test_DS_infunc( DS *ds )
{
struct DS_infunc infunc ;
DS_TRY(ds)
{
DS_GET( ds , char , char_field , & (infunc.ch) )
DS_GET( ds , short , short_field , & (infunc.s) )
DS_GET( ds , int , int_field , & (infunc.i) )
DS_GET( ds , long , long_field , & (infunc.l) )
DS_GET( ds , float , float_field , & (infunc.f) )
DS_GET( ds , double , double_field , & (infunc.d) )
DS_GET( ds , char* , string_field , infunc.buf , sizeof(infunc.buf) )
}
DS_CATCH(ds)
{
printf( "DS_GET failed , LINE[%d] FIELD_NAME[%s] ERROR[%d]\n" , DSGetLastSourceLine(ds) , DSGetFieldName(ds) , DSGetLastError(ds) );
return -1;
}
printf( "--- infunc ---\n" );
printf( "infunc.ch [%c]\n" , infunc.ch );
printf( "infunc.s [%hd]\n" , infunc.s );
printf( "infunc.i [%d]\n" , infunc.i );
printf( "infunc.l [%ld]\n" , infunc.l );
printf( "infunc.f [%f]\n" , infunc.f );
printf( "infunc.d [%lf]\n" , infunc.d );
printf( "infunc.buf[%s]\n" , infunc.buf );
DS_TRY(ds)
{
DS_SET( ds , char , char_field , 'Z' )
DS_SET( ds , short , short_field , 9 )
DS_SET( ds , int , int_field , 87 )
DS_SET( ds , long , long_field , 654321 )
DS_SET( ds , float , float_field , 9.8 )
DS_SET( ds , double , double_field , 7654.3210 )
DS_SET( ds , char* , string_field , "world" )
}
DS_CATCH(ds)
{
printf( "DS_SET failed , LINE[%d] FIELD_NAME[%s] ERROR[%d]\n" , DSGetLastSourceLine(ds) , DSGetFieldName(ds) , DSGetLastError(ds) );
return -1;
}
return 0;
}
struct DS_caller
{
char ch ;
short s ;
int i ;
long l ;
float f ;
double d ;
char buf[ 64 + 1 ] ;
} ;
int test_DS_caller()
{
struct DS_caller caller ;
DS *ds = DS_NEW( "struct_name" ) ;
if( ds == NULL )
{
printf( "DS_NEW failed , errno[%d]\n" , errno );
return -1;
}
memset( & caller , 0x00 , sizeof(struct DS_caller) );
caller.ch = 'A' ;
caller.s = 1 ;
caller.i = 23 ;
caller.l = 456789 ;
caller.f = 1.2 ;
caller.d = 3456.7890 ;
strcpy( caller.buf , "hello" );
DS_TRY(ds)
{
DS_ADD( ds , char , char_field , caller.ch )
DS_ADD( ds , short , short_field , caller.s )
DS_ADD( ds , int , int_field , caller.i )
DS_ADD( ds , long , long_field , caller.l )
DS_ADD( ds , float , float_field , caller.f )
DS_ADD( ds , double , double_field , caller.d )
DS_ADD( ds , char* , string_field , caller.buf )
}
DS_CATCH(ds)
{
printf( "DS_ADD failed , LINE[%d] FIELD_NAME[%s] ERROR[%d]\n" , DSGetLastSourceLine(ds) , DSGetFieldName(ds) , DSGetLastError(ds) );
DS_DELETE( ds )
return -1;
}
test_DS_infunc( ds );
memset( & caller , 0x00 , sizeof(struct DS_caller) );
DS_TRY(ds)
{
DS_GET( ds , char , char_field , & (caller.ch) )
DS_GET( ds , short , short_field , & (caller.s) )
DS_GET( ds , int , int_field , & (caller.i) )
DS_GET( ds , long , long_field , & (caller.l) )
DS_GET( ds , float , float_field , & (caller.f) )
DS_GET( ds , double , double_field , & (caller.d) )
DS_GET( ds , char* , string_field , caller.buf , sizeof(caller.buf) )
}
DS_CATCH(ds)
{
printf( "DS_GET failed , LINE[%d] FIELD_NAME[%s] ERROR[%d]\n" , DSGetLastSourceLine(ds) , DSGetFieldName(ds) , DSGetLastError(ds) );
DS_DELETE( ds )
return -1;
}
printf( "--- caller ---\n" );
printf( "caller.ch [%c]\n" , caller.ch );
printf( "caller.s [%hd]\n" , caller.s );
printf( "caller.i [%d]\n" , caller.i );
printf( "caller.l [%ld]\n" , caller.l );
printf( "caller.f [%f]\n" , caller.f );
printf( "caller.d [%lf]\n" , caller.d );
printf( "caller.buf[%s]\n" , caller.buf );
DS_DELETE( ds )
return 0;
}
int main()
{
return -test_DS_caller();
}