大型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(); }