730 likes | 876 Views
Helpful Hints for C Programming. Paul Stuyvesant. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY. CLARITY.
E N D
Helpful Hints for C Programming Paul Stuyvesant
CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY CLARITY
Clarity • Use space/blank lines to make readable memcpy(&buffer[3],&ecbptr()->ebw000,InputLen); if(*ptr==InputChar) memcpy( &buffer[3], &ecbptr()->ebw000, InputLen); if( *ptr == InputChar )
Clarity • Indent your code int CVZZ( void ) { int LoopCnt = 0; ret = 0; char buffer[20] = { 0 }; if( levtest( D4 ) ) { ret = -1;
Clarity • Just because its less source doesn’t mean less object. if( ++num == 10 ) { num++; // or ++num; if( num == 10 )
#include <stdio.h> main(t,_,a ) char * a; { return! 0<t? t<3? main(-79,-13,a+ main(-87,1-_, main(-86, 0, a+1 ) +a)): 1, t<_? main( t+1, _, a ) :3, main ( -94, -27+t, a ) &&t == 2 ?_ <13 ? main ( 2, _+1, "%s %d %d\n" ) :9:16: t<0?t<-72? main( _, t, "@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+, /#{l,+,/n{n+,/+#n+,/#;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+} e#';dq#'l q#'+d'K#!/+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/+#n';d}rw' i;# ){nl]!/n{n#'; r{#w'r nc{nl]'/#{l,+'K{rw' iK{;[{nl]'/w#q#n'wk nw' iwk{KK{nl]!/w{%'l##w#' i; :{nl]'/*{q#'ld;r'}{nlwb!/*de}'c ;;{nl'-{}rw]'/+,} ##'*}#nc,',#nw]'/+kd'+e}+;#'rdq#w! nr'/ ') }+}{rl#'{n' ')# }'+}##(!!/") : t<-50? _==*a ? putchar(31[a]): main(-65,_,a+1) : main((*a == '/') + t, _, a + 1 ) : 0<t? main ( 2, 2 , "%s") :*a=='/'|| main(0, main(-61,*a, "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}: \nuwloca-O;m .vpbks,fxntdCeghiry") ,a+1);}
On the first day of Christmas my true love gave to me a partridge in a pear tree. On the second day of Christmas my true love gave to me two turtle doves and a partridge in a pear tree. On the third day of Christmas my true love gave to me three french hens, two turtle doves and a partridge in a pear tree. On the fourth day of Christmas my true love gave to me four calling birds, three french hens, two turtle doves and a partridge in a pear tree. On the fifth day of Christmas my true love gave to me five gold rings; four calling birds, three french hens, two turtle doves and a partridge in a pear tree.
Expertise • New to C or C++ for TPF? • Get other people involved • Mix TPFers with C programmers • Peer review a must for new C programmers • There is still a learning curve • Online newsgroups are a fantastic resource
C or C++ • Up to you! • Spend lots of time arguing about it… • Compile C programs as C++ • Better type checking • Can use C++ features such as function overloading • Saves a lot of time later on if you move to full C++ development.
C or C++ • Header files should always have conditional compilation in them • Will save you a lot of hassle later #ifdef __cplusplus extern "C" { #endif int function1( char *, int ); void function2( char, int * ); #ifdef __cplusplus } #endif
C & C++ DLL • Very useful for common routines • Easy for the programmer to create • However … • Make sure programmers know about them • Make them easy to use • Just because you can doesn’t mean you should!
ECB • Still hanging on in there • Defined in c$eb0eb.h • If you want to understand unions this is the place to look • Not necessarily addressed by R9 • Accessed as required by ecbptr() macro
ecbptr()-> #define ecbptr() (*(struct eb0eb **)0x00000514ul) 00042 | * ecbptr()->ebw000 = 'Z'; 0003B2 5810 0514 00042 | L r1,1300 0003B6 92E9 1008 00042 | MVI (*)eb0eb.eb(r1,8),233
ecbptr()-> 5810 0514 L R1,1300 • Load from Base Register 0, offset X’514’ • Address 0 + Prefixing = Prefix Page • Each I/Stream has its own Prefix Page 92E9 1008 MVI 8(R1),233 • Use offset from R1 for ebw000
Useful Compiler Options • AGGR/NOAGGR • Map of structures in compilation • Shows offsets, similar to PRINT GEN • XREF/NOXREF • Shows information for each symbol • Displayed by source line/file/line number
Useful Compiler Options • ARCH( ) • Specify machine architecture • Generates different object code depending on setting • ROSTRINGS • Place R/O strings in program instead of static. • Similar to DC statement
Useful Compiler Options • OPTIMISATION • Code is optimised by compiler • Can give unusual looking results • Make sure you test optimised code • INLINE • Functions may be moved inline • Saves overhead of epilog/prolog
00008 | * int a = 0, 000068 4100 0000 00008 | LA r0,0 00006C 5000 D098 00008 | ST r0,a(,r13,152) 00009 | * b = 2; 000070 4100 0002 00009 | LA r0,2 000074 5000 D09C 00009 | ST r0,b(,r13,156) 00011 | * a += 2; 000078 5800 D098 00011 | L r0,a(,r13,152) 00007C A70A 0002 00011 | AHI r0,H'2' 000080 5000 D098 00011 | ST r0,a(,r13,152) 00013 | * a = b + a; 000084 5810 D09C 00013 | L r1,b(,r13,156) 000088 1A01 00013 | AR r0,r1 00008A 5000 D098 00013 | ST r0,a(,r13,152) 00015 | * a++; 00008E A70A 0001 00015 | AHI r0,H'1' 000092 5000 D098 00015 | ST r0,a(,r13,152) 00017 | * b++; 000096 5800 D09C 00017 | L r0,b(,r13,156) 00009A A70A 0001 00017 | AHI r0,H'1' 00009E 5000 D09C 00017 | ST r0,b(,r13,156) 00019 | * return a + b; 0000A2 58F0 D098 00019 | L r15,a(,r13,152) 0000A6 1AF0 00019 | AR r15,r0 0000A8 47F0 305E 00019 | B @1L3
00007 | * { 00008 | * int a = 0, 00009 | * b = 2; 00010 | * 00011 | * a += 2; 00012 | * 00013 | * a = b + a; 00014 | * 00015 | * a++; 00016 | * 00017 | * b++; 00018 | * 00019 | * return a + b; 000060 41F0 0008 00019 | LA r15,8 00020 | * } 000064 00020 | @1L3 DS 0H
00009 | * strcpy(buffer, name); 0000D8 4100 D0B4 00009 | LA r0,buffer(,r13,180) 0000DC 5000 D0E8 00009 | ST r0,#wtemp_1(,r13,232) 0000E0 41E0 D0B4 00009 | LA r14,buffer(,r13,180) 0000E4 41F0 D0A8 00009 | LA r15,name(,r13,168) 0000E8 4110 0000 00009 | LA r1,0 0000EC 00009 | @1L6 DS 0H 0000EC 5840 308A 00009 | L r4,=A(@@TRT)(,r3,138) 0000F0 DDFF F000 4000 00009 | TRT name(256,r15,0)@@TRT,(r4,0) 0000F6 4770 3062 00009 | BNE @1L7 0000FA D2FF E000 F000 00009 | MVC buffer(256,r14,0)name,(r15,0) 000100 41E0 E100 00009 | LA r14,buffer(,r14,256) 000104 41F0 F100 00009 | LA r15,name(,r15,256) 000108 47F0 3042 00009 | B @1L6 00010C 00009 | @1L7 DS 0H 00010C 1B1F 00009 | SR r1,r15 00010E 4410 6000 00009 | EX r1,#MVC_INST(,r6,0) 000112 5800 D0E8 00009 | L r0,#wtemp_1(,r13,232) 000116 00009 | @1L1 DS 0H
00009 | * strcpy(buffer, name); 0000D4 4100 D0B4 00009 | LA r0,buffer(,r13,180) 0000D8 5000 D0E8 00009 | ST r0,#wtemp_1(,r13,232) 0000DC 4110 D0B4 00009 | LA r1,buffer(,r13,180) 0000E0 4120 D0A8 00009 | LA r2,name(,r13,168) 0000E4 4100 0000 00009 | LA r0,0 0000E8 B255 0012 00009 | MVST r1,r2 0000EC 4710 303E 00009 | BO 62(,r3) 0000F0 5800 D0E8 00009 | L r0,#wtemp_1(,r13,232)
typedef • Use and enforce company wide • It will be a pain when you start • In the long run it will make things easier • Use names that are logical and easy to remember • Place in ‘company’ header file • Do NOT use assembler-ish names!
typedef - example typedef unsigned char Uchar; typedef unsigned short int Uint16; typedef signed short int Sint16; typedef unsigned long int Uint32; typedef signed long int Sint32; typedef int Sint32; DO NOT! typedef unsigned char BYTE; typedef unsigned short int HALFWORD;
typedef • Worth being aware of standard typedefs typedef char dft_alg; typedef char dft_are; typedef unsigned int dft_fad; typedef char dft_fid; typedef struct sw00sr dft_fil; typedef char dft_hdr; typedef struct id_list dft_idl; typedef struct sw01sr dft_kyl;
Pointers • The power of C language • Use correct type of pointer • Calling a function to check a field in specific structure? • Pass in address of field not address of structure. • Function is not then tied to a specific structure.
int Validate_Whatever1 ( struct wa0aa * ); int Validate_Whatever2 ( char * ); void CVZZ(void) { int ret = 0; struct wa0aa *AaaPtr = ecbptr()->ebccr1; // Validate_Whatever is tied to wa0aa structure ret = Validate_Whatever1( AaaPtr ); // Validate_Whatever2 can be used for any char pointer ret = Validate_Whatever2( &(AaaPtr->wa0xxx) );
Oops Pointers struct xxx *pXData = calloc( 1, sizeof(struct xxx) ); Later a change is made to structure type struct yyy *pXData = calloc( 1, sizeof(struct xxx) );
Pointers struct xxx *pXData = calloc( 1, sizeof( *pXData ) ); Later a change is made to structure type struct yyy *pXData = calloc( 1, sizeof( *pXData ) );
Pointers • Pointer and array notation are interchangeable • Don’t mix and match within same function • Causes confusion • Is just not good practice • Array notation can sometimes be clearer
void functionX( char *pMi0acc ) { char option = *pMi0acc; option = pMi0acc[0]; if( *(pMi0acc+1) == ‘A’ ) if( pMi0acc[1] == ‘A’ )
Pointers • All pointer types can be dereferenced • Use this facility to move data around struct wa0aa *pWa0aa = ecbptr()->ebccr1, *pScrWa0aa = NULL; pScrWa0aa = calloc( 1, sizeof( *pWa0aa)); memcpy( pScrWa0aa, pWa0aa, sizeof( *pWa0aa)); OR *pScrWa0aa = *pWa0aa;
Converting DSects • Dsect are for Assembler Programs • Does exact equivalent help with C or C++? • Try to identify separate structures and declare individually. • Place in C/C++ source file when developing • Move to header when completed • Use AGGR option in compile to view offsets • More later in TPFDF discussion
Functions • Too many parameters - consider parameter list structure. • Try to keep functions simple, easier said than done. • Avoid overuse of #define to ‘simplify’ function calls.
struct param_list { char *pImsg; char *pOutput; }; int Validate_Input( struct param_list * ); void CVZZ(void) { struct param_list parms = { 0 }; struct mi0mi *miptr = ecbptr()->ebccr0; int ret = 0; parms.pOutput = calloc( 1, 10000 ); parms.pImsg = miptr->mi0acc; ret = Validate_Input( &parms );
struct param_list { char *pImsg; char *pOutput; int CharCount; }; int Validate_Input( struct param_list * ); void CVZZ(void) { struct param_list parms = { 0 }; struct mi0mi *miptr = ecbptr()->ebccr0; int ret = 0; parms.CharCount = miptr->mi0cct - 4; parms.pOutput = calloc( 1, 10000 ); parms.pImsg = miptr->mi0acc; ret = Validate_Input( &parms );
#define & functions PCS_Link ( p_PCS_Ent, d_PCS_Buff, p_PCS_Last_Ent, p_PCS_Next_Ent_Item, st_PCS_Ent_Item ); #define PCS_Link(NEW, BUFFER, PREVIOUS, NEXTFIELD, STRUCT) \ ( PCS_BuffGet(NEW,BUFFER,sizeof(STRUCT)), \ *PREVIOUS = NEW, \ PREVIOUS = (STRUCT **) &(NEW->NEXTFIELD) ) #define PCS_BuffGet(NEW,BUFFER,SIZE) \ ( ( (NEW = XXBuffGet(BUFFER,SIZE)) != NULL ) ? \ ( TRUE ) : \ ( snapc (SNAPC_RETURN, 0xB00B00, "NO MORE BUFFER", \ NULL, 'U', SNAPC_REGS, SNAPC_ECB, "PCS000"), \ exit (1), \ FALSE ))
Default Values • Most functions have default values ptr = dfopn( FNAME, FID, 0 ); • What does the 0 in dfopn actually mean? • Take a look in c$cdfeq.h • Contains values used by the various commands • These are usually the dft_opt parameter
Default Values #define DFOPN_ALG 0x00000001UL #define DFOPN_FADDR 0x00000002UL #define DFOPN_ORD 0x00000004UL #define DFOPN_SPACE 0x00000008UL #define DFOPN_TAPE 0x00000010UL #define DFOPN_AREA 0x00000020UL #define DFOPN_HOLD 0x01000000UL #define DFOPN_NOHOLD 0x00000000UL #define DFOPN_DLI 0x00000000UL #define DFOPN_DETAC 0x00008000UL #define DFOPN_NODET 0x00000000UL
Default Values • Understanding can make problem solving easier. find_record( D6, NULL, “PS”, 0, UNHOLD); • Why does the above line compile OK but cause Control 8 at exit?
Default Values find_record( D6, NULL, “PS”, 0, UNHOLD); /* FIND/FILE constants */ enum t_act {NOHOLD, UNHOLD, NOREL}; #define HOLD UNHOLD find_record( D6, NULL, “PS”, 0, HOLD);
TPFDF • Error Handling • Use DF_SERRC macro • Converting DSECT to Header • Separate structures for each LREC • Understand the typedefs and defines • Check the cdf header files
Error Handling • Use built in macros in C$CDFERR.h • DF_SERRC can be particularly useful • Check if dump already taken by TPFDF such as DB0100 or DB0102 • Do not repeat dump if already taken
pk40lrec = dfred( PCSFile, 0 ); if( DF_OK( PCSFile ) ) { // Found Record process } else if( DF_NR( PCSFile ) ) { // Not Found process } else { serrc_op( SERRC_RETURN, 0xC0FFEE, "OH NO - NOT AGAIN", NULL); }
pk40lrec = dfred( PCSFile, 0 ); if( DF_OK( PCSFile ) ) { // Found Record process } else if( DF_NR( PCSFile ) ) { // Not Found process } else { if( !(DF_SERRC( PCSFile ))) { serrc_op( SERRC_RETURN, 0xC0FFEE, "OH NO - NOT AGAIN", NULL); } }
DSect Conversion • Each Lrec type should be separate structure. • No need to build ‘overall’ structure • Makes header much easier to read • Why pretend it is Assembler?
GR99REC&CG1 DS 0CL1 1ST RECORD START (1=VARIABLE,ELSE SIZE) GR99SIZ&CG1 DS H SIZE OF LOGICAL RECORD GR99KEY&CG1 DS X LOGICAL RECORD IDENTIFIER ********************************************************************* * DATA DEFINITIONS * ********************************************************************* AIF ('&GR99RR1' EQ '1').KEYEQ GO IF NOT FIRST ISSUE #GR99K40 EQU X'40' LOGICAL RECORD KEY X'40' #GR99L40 EQU GR99E40&CG1-GR99REC&CG1 LENGTH OF RECORD KEY X'40' #GR99K50 EQU X'50' LOGICAL RECORD KEY X'50' #GR99L50 EQU GR99E50&CG1-GR99REC&CG1 LENGTH OF RECORD KEY X'50' &GR99RR1 SETB 1 INDICATE 1ST TIME THROUGH .KEYEQ ANOP GENERATE DSECT NAME GR99ORG&CG1 EQU * START OF LOGICAL RECORD DESCRIPTION ********************************************************************* * DESCRIPTION OF X'40' LOGICAL RECORD TYPE ********************************************************************* GR99FIX&CG1 DS CL8 NUMBER OF LAST MESSAGE IN TABLE GR99FRX&CG1 DS CL8 NUMBER OF FIRST MESSAGE IN TABLE GR99IND&CG1 DS X INDICATOR GR99NBX&CG1 DS H NUMBER OF MESSAGES IN TABLE GR99E40&CG1 EQU * END OF LOGICAL RECORD KEY '40' ORG GR99ORG&CG1
********************************************************************* * DESCRIPTION OF X'50' LOGICAL RECORD TYPE ********************************************************************* GR99LNO&CG1 DS CL2 LANGUAGE CODE - NUMBER GR99NAM&CG1 DS CL10 LANGUAGE NAME GR99LNN&CG1 DS XL1 LANGUAGE CODE - BINARY GR99LST&CG1 DS CL8 NUMBER OF LAST MESSAGE GR99E50&CG1 EQU * END OF LOGICAL RECORD KEY '50' ORG GRXXORG&CG1 DBRED REF=GR99PS,REG=R2,ERROR=ERRORLAB, * KEY1=(PKY=#GR99K40)#IF SW00RTN,EQ,Z MVC EBW000(L’GR99LNO),GR99LNO
struct gr99rec { dft_siz gr99siz; dft_key gr99key; union lrecs { struct k40lrec { char _gr99fix[8]; char _gr99frx[8]; char _gr99ind; unsigned short int _gr99nbx; } Key40Lrec; struct k50lrec { char _gr99lno[2]; char _gr99nam[10]; char _gr99lnn; char _gr99lst[8]; } Key50Lrec; } LrecStructs; }; #define gr99fix LrecStructs.Key40Lrec._gr99fix #define gr99frx LrecStructs.Key40Lrec._gr99fix #define gr99lnn LrecStructs.Key50Lrec._gr99lnn
dft_fil *pGr99fil = NULL; dft_kyl keys = { 0 }; struct gr99rec *pLrec = NULL; pGr99fil = dfopn( GR99FNAME, GR99FID, 0 ); SetUpKeys( pGr99fil, &keys ); pLrec = dfred( pGr99fil, 0 ) if( DF_OK( pGr99fil ) ) { ecbptr()->ebw000 = pLrec->gr99lnn // Key 50 lrec ecbptr()->ebw000 = pLrec->gr99ind // Key 40 lrec