Title: | VAX C Notes |
Notice: | READ 1.* BEFORE WRITING; USE KEYWORDS TO FIND EXISTING NOTES |
Moderator: | DECC::VMCCUTCHEON |
Created: | Sat Jan 25 1986 |
Last Modified: | Mon Jun 02 1997 |
Last Successful Update: | Fri Jun 06 1997 |
Number of topics: | 5611 |
Total number of notes: | 27963 |
When running the following program the result is that the first variable named 'mt' is incorrectly displayed. ALl other variables (including mt2 which is also declared as DOUBLE like is defined mt) are correctly displayed. This same program works fine on Vax. The problem ocurs only on Axp. Any help is greatly welcome ... Thanks in advance. Jean-Pierre ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ***> - main program: /* paye ***************************************************************** * menu general de la paye * ************************************************************************/ /* # include "appli.h" # include "fenetre.h" exec sql include sqlca.h; */ #define S_NORMAL 0 main() { char ch[81]; short fen, ish; long lsh; double mt2, mt; mt = 13456.45; mt2 = 22222.55; ish = 345; lsh = 123456L; s_pr( fen, 4, 5, S_NORMAL, "Montant : %9.02lf mt2:%8.02lf", mt, mt2); s_pr( fen, 10, 5, S_NORMAL, "Chaine: %s _ %s", "chaine1", "chaine2"); s_pr( fen, 12, 5, S_NORMAL, "Short: %d _ %d", 23, 44); s_pr( fen, 14, 5, S_NORMAL, "Long : %ld _ %ld", 123456L, 4567890L); /* getchar(); */ } ***> - function called: /*s_pr************************************************************************ * affichage dans une fenetre d'un ecran virtuel * *****************************************************************************/ # include "fenetre.h" s_pr(num,lig,col,type,cmd,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) char *cmd; int num, lig, col, type; { char ch1[80], data[80]; int i, j; $DESCRIPTOR (dat,data); printf("\nDEBUT S_PR"); printf("\nS_PR _ DATA:%s", data); sprintf(data,cmd,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); printf("\nS_PR _ CMD :%s", cmd); printf("\nS_PR _ DATA:%s", data); dat.dsc$w_length = strlen(data); /** i = SMG$PUT_CHARS(&fenetre[num].num_fenetre,&dat,&lig,&col,0,&type); **/ /*else s_erreur(i);*/ } ***> - procedure to create the .EXE: $ cc/stand=VAXC/deb/noop/float=d_float/member titi $ cc/stand=VAXC/deb/noop/float=d_float/member s_pr $ link/deb titi,s_pr,sys$library:vaxcrtld/lib $ del/log/noconf *.obj;* $ pu $ exit ***> - appli.h: # define OUI 1 # define NON 2 # define OK 1 # define NOK 0 # define AUTRE 0 # define RESEAU 1 # define BATCH 2 # define INTERACTIF 3 # define DIRECTE 1 # define DIFFERE 2 # define NORMAL 1 # define NOR_VIDEO 1 # define INVERSE 2 # define INV_VIDEO 2 # define CLIGNOTE 3 # define SOULIGNE 4 # define INTENSE 5 # define SLSH 6 # define DLSH 7 # define DLDH 8 # define PHYSIQUE 1 # define VIRTUEL 2 # define J 0 /* JOUR pour stdrt */ # define M 1 /* MOIS pour strdt */ # define A 2 /* AN pour strdt */ # define JJMMAA 1 # define JJMM 2 # define MMAA 3 # define SRT 4 # define SHORT 5 # define LONG 6 # define CODE 7 # define JJMMAAAA 8 # define BS 127 # define VALIDER 270 # define RETN 13 # define HOME 7 # define KEY_RIGHT 277 # define KEY_LEFT 276 # define KEY_UP 274 # define KEY_DOWN 275 # define NEXT_PAGE 316 # define PREV_PAGE 315 # define INSRT_CHAR 11 # define DEL_CHAR 12 # define INSRT_LINE 13 # define DEL_LINE 14 # define RECH 311 # define SELECTION 314 # define DEL 127 # define BELL '\007' # define F1 291 # define F2 292 # define F3 293 # define F4 294 # define F5 295 # define F6 296 # define F7 297 # define F8 298 # define F9 299 # define F10 300 # define PF1 256 # define PF2 257 # define PF3 258 # define PF4 259 ***> - fenetre.h: /*fenetre********************************************************************* * header du gestionnaire d'ecran C-VMS (SMG$) * *****************************************************************************/ # include <stdio.h> /* # include <car.h> */ # include descrip # include smgdef # define S_MAX_FENETRE 300 # define NETWORK 1 # define BATCH 2 # define INTERACTIF 3 # define OK 1 # define NOK 0 # define S_OUI 1 # define S_NON 2 # define S_VISIBLE 1 # define S_INVISIBLE 2 # define S_HORI 1 # define S_VERT 2 # define S_NORMAL 0 # define S_INVERSE SMG$M_REVERSE # define S_SOULIGNE SMG$M_UNDERLINE # define S_INTENSE SMG$M_BOLD # define S_CLIGNOTE SMG$M_BLINK # define S_DOWN SMG$M_DOWN # define S_UP SMG$M_UP # define S_RIGHT SMG$M_RIGHT # define S_LEFT SMG$M_LEFT # define S_LIGNE 1 # define S_PAGE 2 # define S_DEMIPAGE 3 # define S_PAGE_1 4 # define REMPLACEMENT 1 # define INSERTION 2 # define SAI_STR 1 # define SAI_NBR 2 # define SAI_DEC 3 # define SAI_HR 4 # define SAI_JMA 5 # define SAI_JMAA 6 char s_user[30]; char s_application[30]; int s_num_pid; int s_num_clavier; int s_num_ecran_physique; struct fenetre { short etat; int num_fenetre; short lig; short col; } fenetre[S_MAX_FENETRE]; # define MAX_NIVEAU 5 # define MAX_CHOIX 20 struct menu0 { char lib_sup[30]; char lib_inf[30]; short col; short lg; short action; } menu0[9]; struct ss_menu { short max_menu; struct menu { int num_fenetre; short max_lib; short max_lg; char lib[MAX_CHOIX+1][70]; short type[MAX_CHOIX+1]; short action[MAX_CHOIX+1]; } menu[100]; } ss_menu[MAX_NIVEAU+1]; struct param_menu { short premier_passage; short nb_menu0; int num_menu0; int num_pied; short menu0_val; short menu_val[MAX_NIVEAU+1]; short menu_lig[MAX_NIVEAU+1]; short niveau; }; struct param_menu param_menu = {S_OUI,0,0,0,0}; struct def_sai_code { char choix[300][60]; short nb; } def_sai_code; struct param_saisie { short mode; short num_pied; short lg; char ch_initiale[256]; double bmin; double bmax; } param_saisie; ***************************************************************************** ... Here is a Debugger Log file: g !break at routine TITI\main ! 23: mt = 13456.45; Step !stepped to TITI\main\%LINE 24 ! 24: mt2 = 22222.55; Step !stepped to TITI\main\%LINE 25 ! 25: ish = 345; Step !stepped to TITI\main\%LINE 26 ! 26: lsh = 123456L; Step !stepped to TITI\main\%LINE 27 ! 27: s_pr( fen, 4, 5, S_NORMAL, "Montant : %9.02lf mt2:%8.02lf", exa/d_float mt !TITI\main\mt: 13456.4500000000 exa/d_float mt2 !TITI\main\mt2: 22222.5500000000 step/into !%DEBUG-I-DYNMODSET, setting module S_PR !stepped to S_PR\s_pr\%LINE 4316 ! 4316: $DESCRIPTOR (dat,data); Step !stepped to S_PR\s_pr\%LINE 4318 ! 4318: printf("\nDEBUT S_PR"); exa/d_float arg0 !S_PR\s_pr\arg0: -0.173211716118183E+35 <***************** problem **** exa/d_float arg1 !S_PR\s_pr\arg1: 22222.5500000000 Step !stepped to S_PR\s_pr\%LINE 4319 ! 4319: printf("\nS_PR _ DATA:%s", data); Step !stepped to S_PR\s_pr\%LINE 4321 ! 4321: sprintf(data,cmd,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); Step !stepped to S_PR\s_pr\%LINE 4323 ! 4323: printf("\nS_PR _ CMD :%s", cmd); exa cmd !S_PR\s_pr\cmd: 131088 exa data !S_PR\s_pr\data[0:79] ! [0]: 77 ! [1]: 111 ! [2]: 110 ! [3]: 116 ! [4]: 97 ! [5]: 110 ! [6]: 116 ! [7]: 32 ! [8]: 32 ! [9]: 32 ! [10]: 32 ! [11]: 58 ! [12]: 32 ! [13]: 45 ! [14]: 49 ! [15]: 55 ! [16]: 51 ! [17]: 50 ! [18]: 49 ! [19]: 49 ! [20]: 55 ! [21]: 49 ! [22]: 54 ! [23]: 49 ! [24]: 49 ! [25]: 56 ! [26]: 49 ! [27]: 56 ! [28]: 51 ! [29]: 51 ! [30]: 48 ! [31]: 49 ! [32]: 48 ! [33]: 48 ! [34]: 48 ! [35]: 48 ! [36]: 48 ! [37]: 48 ! [38]: 48 ! [39]: 48 ! [40]: 48 ! [41]: 48 ! [42]: 48 ! [43]: 48 ! [44]: 48 ! [45]: 48 ! [46]: 48 ! [47]: 48 ! [48]: 48 ! [49]: 46 ! [50]: 48 ! [51]: 48 ! [52]: 32 ! [53]: 32 ! [54]: 109 ! [55]: 116 ! [56]: 50 ! [57]: 58 ! [58]: 50 ! [59]: 50 ! [60]: 50 ! [61]: 50 ! [62]: 50 ! [63]: 46 ! [64]: 53 ! [65]: 53 ! [66]: 0 ! [67]: 0 ! [68]: 0 ! [69]: 0 ! [70]: 0 ! [71]: 0 ! [72]: 108 ! [73]: 54 ! [74]: 81 ! [75]: 0 ! [76]: 0 ! [77]: 0 ! [78]: 0 ! [79]: 0 Step !stepped to S_PR\s_pr\%LINE 4324 ! 4324: printf("\nS_PR _ DATA:%s", data); Step !stepped to S_PR\s_pr\%LINE 4326 ! 4326: dat.dsc$w_length = strlen(data); exa/d_float arg0 !S_PR\s_pr\arg0: -0.173211716118183E+35 <******* problem ******* go !%DEBUG-I-EXITSTATUS, is '%SYSTEM-S-NORMAL, normal successful completion' exit
T.R | Title | User | Personal Name | Date | Lines |
---|---|---|---|---|---|
5611.1 | DECC versions used for my tests. | PADKOA::COSTEUX | France: pays d'assist�s... | Mon Jun 02 1997 11:45 | 3 |
Forgot to mention that I get the same behavior on Axp using either DECC-V5.3-006 or DECC-V5.5-003 | |||||
5611.2 | SPECXN::DERAMO | Dan D'Eramo | Mon Jun 02 1997 12:27 | 42 | |
<<< CLT::DISK$CLT_LIBRARY3:[NOTES$LIBRARY]SMG.NOTE;1 >>> -< Screen ManaGement Discussions >- ================================================================================ Note 1567.4 SMG$PUT_CHARS problem on AXP. 4 of 4 SPECXN::DERAMO "Dan D'Eramo" 36 lines 2-JUN-1997 11:22 -------------------------------------------------------------------------------- You just can't do this...it isn't legal C. It doesn't work. > s_pr( fen, 4, 5, S_NORMAL, "Montant : %9.02lf mt2:%8.02lf", > mt, mt2); >s_pr(num,lig,col,type,cmd,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) > >char *cmd; >int num, lig, col, type; > >{ [...] > sprintf(data,cmd,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); The only way to write s_pr is to prototype it with the "..." before calling it and then define it using <stdarg.h>. Dan #include <stdarg.h> void s_pr(int num, int lig, int col, int type, const char *cmd, ...); /* Now that the above prototype has been seen it is okay to call s_pr. */ /* Here's how the definition calls sprintf... */ void s_pr(int num, int lig, int col, int type, const char *cmd, ...) { va_list ap; char data[80]; va_start(ap, cmd); vsprintf(data, cmd, ap); va_end(ap); /* ... */ } | |||||
5611.3 | OK. But why a pb. only for the first variable? | PADKOA::COSTEUX | France: pays d'assist�s... | Mon Jun 02 1997 12:49 | 5 |
I don' t understand as there is no problem with other variables to print but the variable mt only .. I'm not a C expert so it's difficult to understand... Jean-Pierre | |||||
5611.4 | Use Correct Syntax... | XDELTA::HOFFMAN | Steve, OpenVMS Engineering | Mon Jun 02 1997 13:53 | 16 |
The variable-argument-list functions look at the argument list to determine how many arguments are passed -- there is either an explicit number of arguments passed via the argument list (this can be explicitly passed as an argument on either platform, or it can be read via the call list on VAX), or via implicit mechanisms such as the printf control string or the pattern of arguments. From this, the routine can determine the number of arguments... As for why this works -- C has a calling standard waiver around passing quadword-sized arguments (doubles) by value on VAX -- these take up two longword argument positions in the call stack. I'd suspect this difference was involved here. Bottom line: fix the code. | |||||
5611.5 | You lied about the types, and got caught | WIBBIN::NOYCE | Pulling weeds, pickin' stones | Mon Jun 02 1997 17:11 | 45 |
>s_pr(num,lig,col,type,cmd,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) > >char *cmd; >int num, lig, col, type; > >{ This declaration says that arg0, arg1, ..., arg9 all have type "int". When you pass an argument of a different type, things may go wrong. On Alpha, the first 6 arguments are passed in registers -- integer arguments in integer registers, and floating arguments in floating registers. Thus, num, lig, col, type, cmd, and arg0 are expected to arrive in the 6 integer argument registers, while arg1, arg2, ..., arg9 are expected to arrive in memory. > s_pr( fen, 4, 5, S_NORMAL, "Montant : %9.02lf mt2:%8.02lf", > mt, mt2); This call passes fen, 4, 5, S_NORMAL, and the string pointer in the first 5 integer argument registers. It passes mt in the 6th floating argument register, and it passes mt2 in memory. When s_pr copies arg0 for the call to sprintf, it gets an uninitialized value out of the 6th integer argument register, and places it in the 3rd integer argument register (after data and cmd). That's why you see garbage printed. (Why does mt2 work? s_pr gets the right data -- or at least the low longword of the right data, so you get 7 significant digits -- out of memory, and puts it into the 4th integer argument register. But sprintf ought to expect a floating argument for a "%ld" item. This works, approximately, because of magic flags passed in the "Argument Information" register (R25) that tell sprintf (and other stdargs routines) where their arguments were actually passed. The "AI" register isn't used on Digital UNIX or Windows NT, so this wouldn't work there. Also, those systems only support IEEE floating types, where the most significant part of a double is in the higher-addressed half, not the lower-addressed half as for the VAX types.) The proper solution is to recode s_pr to use the stdarg mechanism. If that turns out to be really difficult, you could hack around it by passing an extra parameter to s_pr, so that arg0 is pushed out to the 7th position, and gets passed in memory instead of in a register. If you declare arg0 thru arg9 as __int64 on Alpha, you won't even lose precision But this is really a hack -- you should use the stdarg mechanism. | |||||
5611.6 | SPECXN::DERAMO | Dan D'Eramo | Mon Jun 02 1997 18:33 | 31 | |
In comparison to .-1, here is why you "got away with it" on OpenVMS VAX. The call > s_pr( fen, 4, 5, S_NORMAL, "Montant : %9.02lf mt2:%8.02lf", > mt, mt2); created an arglist with longword count 9 followed by longwords fen, 4, 5, S_NORMAL, "Montant...", mt (lo), mt (hi), mt2 (lo), mt2 (hi) The declaration >s_pr(num,lig,col,type,cmd,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) > >char *cmd; >int num, lig, col, type; caused s_pr to pick up these 9 longwords into arguments num,lig,col,type,cmd,arg0,arg1,arg2,arg3. The call to sprintf in s_pr built up sprintf's argument list in exactly the same way sprintf would have seen it if you had passed the format string and mt and mt2 to sprintf directly. Lots of older C compilers passed arguments in consecutive memory locations like that, and the code would probably have appeared to work fine using any of them. But once it was ported to a system where arguments were passed in registers the underlying nonportability was revealed. That's why <stdarg.h> was standardized, any ANSI C vendor has to make it work no matter how the compiler passes arguments. Dan |