大型C工程中存在模块与模块之间传递结构体的编译一致性问题,由于C是静态语言,编译后结构体成员都固化为地址偏移量,当结构体定义变更后必须保证相关模块全编译,不然会破坏进程栈且程序没法主动发现。
InterBankPlus交易管理层精心设计了动态结构DS机制,解决了全编译问题,并作了大量使用细节封装,使得使用尽量方便。
调用者模块先DS_NEW一个动态结构DS,DS_ADD输入变量、变量类型、值,而后调用被调用者模块入口函数,被调用者模块从动态结构中DS_GET出变量,处理后DS_SET回动态结构,返回调用者模块,调用者模块DS_GET输出变量,最后DS_DELETE动态结构。
模块内部仍是建议使用静态结构体,由于内部通常都是编译一致的。
经过动态结构DS机制,模块之间能够安全的传递数据,至多也可被程序主动发现报错,不至于被动的形成进程异常。
小技术解决大问题。git
#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(); }