mjs@hubcap.clemson.edu (M. J. Saltzman) (04/21/91)
Well, I just found this bug, too, in Turbo C++ v2.0. Since it's a current topic of conversation, I thought I'd toss in my experience with it. In article <26502@hydra.gatech.EDU>, jt2@prism.gatech.EDU (TROSTEL,JOHN M) writes: |> In article <1991Apr16.141117.5065@odin.diku.dk> juul@diku.dk (Anders Juul Munch) writes: |> >cn@allgfx.agi.oz (Con Neri) writes: |> > |> >>Hi netters, |> >> I havec been working with a friend developing some code using |> >>Turbo C++ V1.5 but only writing in standard C. We have been getting an error |> >>with a particular piece of code, namely |> > |> >> fscanf(fp,"%f", &f); |> > |> >> The runtime error is |> > |> >> scanf: floating point formats not linked |> >> Abnormal Program termination. |> > |> >> Can some one shed some light on what this means? |> i have found the same problem. The way I worked around it was to declare |> a new float variable, say fl_var, and use it to read in my data. See old |> and new code below: |> In <1991Apr17.143139.20903@ira.uka.de> krey@i30fs1 (Andreas Krey) responds: AK>Sorry to say so, but that is probably something unrelated. The problem AK>with 'scanf: floating point formats not linked' is with the libraries. AK>Most users of printf/scanf don't do floating point and the standard library AK>code of printf/scanf cannot convert that. You have to set a compiler AK>flag/option to include the variant capable of float conversion when linking. AK>(Cannot name the option, I only know this feature from a little C compiler.) Actually, this seems to be the crux of the matter. As to the compiler option, Turbo C++ includes an option to *exclude* the FP libraries, even if the compiler thinks they're necessary, but if the compiler determines that no FP library is needed, it will not include it, no matter what command line options you use. The particular circumstances under which the error occurs seems to be when you pass the value of a (float *) variable to scanf (as opposed to the address of a float). It doesn't seem to be enough to require floating point *operations* in the code to override the problem; you need to include a call to a FP *function* from the math.h header. You can also read directly into a float. If you do this anywhere in the code, the problem disappears. |> OLD CODE: |> |> ... |> float *f_ptr; |> ... |> f_ptr = (float *)calloc(...); |> ... |> fscanf(file,"%f",f_ptr); |> ... |> ^----- gives the run time error |> |> NEW CODE: |> ... |> float *f_ptr, new_var; |> ... |> f_ptr=(float *)calloc(...); |> ... |> fscanf(file,"%f",&new_var); |> f_ptr[i] = new_var; /* i'm inside a loop here */ |> .... |> ^------ this code works!!?? |> |> Well, I can't figure it! Nothing else was changed in the program to |> make it work. That is it DIDN'T like the address sent to it with |> using just 'f_ptr' but DID like the address it got with '&new_var'. |> |> Anyone else figure this out more? Anyone from Borland about to tell |> us how to fix this? |> AK>This is either a compiler bug (improbable), oder something with AK>the memory models. new_var is on the stack, f_ptr points to the heap; AK>looks like far/near pointer trouble. That is, passing the wrong pointer AK>type. Nope. This time it seems to be a compiler bug. The above is one way to work around it. The other is to call a math.h function. Then, in <1991Apr18.021515.1481@athena.mit.edu>, scs@adam.mit.edu (Steve Summit) writes: SS>This issue faintly amazes me. I can't believe that: SS>1. there are still people who have not heard about this problem, SS>2. Borland apparently still hasn't fixed it, SS>3. the problem exists in the first place, and SS>4. so many programs manage to elicit it. SS>(Neither 1 nor 4 are flames; I'm just, as I say, faintly amazed.) Well, even so, I don't write code every day, so I don't keep up with this group that much. Enough programs probably don't eleicit it that many people never encounter it. I called Borland, and they suggest calling the dummy math function as a workaround. I don't know why they haven't fixed it either. SS>[most of explanation of bug mechanism deleted] SS>How does the compiler determine that a "program uses floating SS>point?" Ritchie's compiler asserts that a program uses floating SS>point if a variable is declared as float or double (or, as I SS>recall, a pointer to same), and if that variable is then used. SS>(Even this heuristic isn't perfect; Doug Gwyn claims to have SS>augmented it to handle a few more, really obscure cases, but I SS>don't know the details -- perhaps they involve casts.) Turbo C SS>apparently asserts that a program uses floating point only if the SS>program actually calls for floating point arithmetic. This can't be it. I think it must check to see if the address of a float is passed to scanf, but miss the case where a pointer to a float is passed. Actually doing floating point has no effect on the bug, although calling a floating point library function does. SS>I don't know why Turbo C uses such an obviously inadequate SS>heuristic, particularly when a simple, correct one exists (and SS>was used by a highly visible, 15 year old compiler). It may be SS>that the printf float/nofloat decision is driven by the (equally SS>broken) PC floating-point-via emulator/coprocessor/both/neither SS>distinction, rather than by a "magic" extra undefined external SS>(which is how Ritchie's compiler did it, with the symbol __fltused). SS>I'm sure that the folks on comp.os.msdos.programmer (where this SS>discussion really belongs, and to where followups have been SS>redirected) could provide more information. I suspect that Borland started with something like Ritchie's heuristic, then outsmarted themselves trying to recognize more cases where they could save. I don't know for sure. There hasn't been any discussion on comp.sys.msdos.programmer yet. Maybe this will start some. SS>(I have heard that recent releases of Turbo C finally manage to SS>correct this problem. I would appreciate any confirmation of SS>this rumor.) Not as of Turbo C++ version 2.0. When I called, they did not offer an upgraded interim release as a fix, even though one apparently exists. SS>The remaining puzzle is why so many programs are bitten by this SS>bug. How many real programs read floating point values in and SS>printf them back out (or printf compile-time floating point SS>constants) without doing any arithmetic on them? (This is not to SS>blame the victim, or to excuse Borland for having the bug. The SS>test programs which are used to demonstrate the bugs are always SS>stripped down, as bug-demonstrating test programs should be. I SS>wonder why the longer programs from which the test programs were SS>stripped down managed not to do enough floating-point arithmetic SS>to trigger proper linking? Perhaps the problem only comes up SS>when people write little test programs to play with printf SS>floating-point specifiers, and there are enough of those little SS>test programs to account for the frequency of the question.) Well, my application was a problem generator for an optimization package. It allocates some arrays, reads values into them, then does simple arithmetic to produce an output file with many more numers in it. I actually encountered the problem for the first time when I was trying to write the input portion, and was just echoing the input, but the final version of the program also fails, since the arithmetic is too simple (no library calls), and no values are read into floats on the stack. Finally, in <1991Apr16.091320.29937@monu6.cc.monash.edu.au>, ron@monu6.cc.monash.edu.au (Ron Van Schyndel) writes: RVS>Congratulations! You have found the famous MATH bug, present in most C RVS>compilers (at least, *I* think its a bug). No argument here! (Maybe most *DOS* C compilers...) RVS>When TC compiles your program, it keeps track of whether floating point RVS>instructions were actually GENERATED. In your code above, a MEMORY ADRESS RVS>is passed to some unknown (TC doesn't know what FSCANF is - it's linked in RVS>later) function. That doesn't cause floating point code to be generated. RVS>Thus, the compiler does not cause the floating point library to be linked in, RVS>and it is only at runtime that this is detected. Well, that's apparently not exactly the mechanism, at least in Turbo C++ (see above). Don't know about other compilers. RVS>Be happy for the error message, MS C version 4 and earlier would simply hang RVS>in this situation. Ick. RVS>I think this is a bug, since even if you include the -f or -f87 option, telling RVS>the compiler EXPLICITLY that you want floating point included, it will still RVS>NOT include it in the above situation. It's fine for the compiler to try and second-guess you (if it does a good job in most circumstances), but no heuristic will cover every case. It's beyond me why Borland provides the ability to explicitly *exclude* the FP libraries, in case the compiler wrongly includes them, but they don't provide an option to *include* them when the compiler erroneously leaves them out. It seems reasonable to make this a separate decision from that of *which* library to use, if one is needed at all. RVS>The fix? Include the following before the FSCANF. RVS> RVS> f = 3.0 * i; /* where i is ANY variable whose value cannot */ RVS> fscanf(fp,"%f", &f); /* be anticipated by the compiler */ RVS> RVS>The f will get immediately overwritten by the FSCANF, but the compiler will RVS>now be forced to include the floating point library code. You probably got the value for i by reading it with scanf(). This fix doesn't work if you don't (see above again). RVS>Hope this helps, RON I hope I've added something to the discussion. (OK, *now* let's followup to comp.os.msdos.programmer). Matthew Saltzman mjs@clemson.edu