INF: C Compiler: _control87() and Modifying the Control Word

ID Number: Q42781

5.00 5.10 6.00 6.00a 6.00ax 7.00 | 5.10 6.00 6.00a

MS-DOS | OS/2

Summary:

In Microsoft C versions 5.0, 5.1, 6.0, 6.0a, 6.0ax, and C/C++ version

7.0, you cannot mask or unmask certain bits with _control87(), even

though it will report that it was successful. Also, modifying certain

bits of the control word yourself (with the 80X87 instruction FLDCW)

will corrupt all subsequent floating-point C run-time operations.

More Information:

The documentation in FPEXCEPT.DOC (which is contained in the C 5.1

package and also contained in the Knowledge Base) states that

denormals are always masked off and that invalids are never masked.

It also states that bits 7, 6, 1, and 0 in the control word cannot be

modified. It is true that these bits cannot be modified with the

function _control87(); however, if you look at the control word with

an assembly routine, you will see that the control word does not hold

the same value as the C run time would have you believe.

Invalid exceptions cannot be masked, because the C run time uses them

internally to handle extending the 80x87 floating-point stack beyond

eight stack elements. If you try to mask invalid with the C run time,

you will be told that you were successful, but the control word will

not be changed at all. No invalid exceptions will ever reach you. If

you try to mask invalid and an invalid exception occurs (which doesn't

have anything to do with stack overflow or underflow), the C run time

will check to see if you tried to mask invalid. If you did, the

floating point routines will simply ignore the mask. If you mask

invalid by setting the control word from an assembly routine with

FLDCW, the run time will have stack problems.

As for denormals, the denormal exception is never masked internally,

because every time the 80x87 encounters a denormal number, the

emulator will try to convert it to a normalized number. This is the

masked behavior on an 80387. Because this should not be changed

(because it will break our math routines), you should treat denormals

as if they are always masked. Thus, denormals always appear to be

masked; you will never see a denormal exception, because they are all

handled internally by the emulator.

Therefore, denormals always appear to be masked unless you look at the

control word on the chip directly, by using an FSTCW or CodeView.

Also, it will appear that invalids can be masked, unless you look at

the chip directly. If you do look at the chip directly, you will see

that nothing has changed when trying to mask an invalid with

_control87. Therefore, the code is functioning as expected. Both

invalid and denormal are unmasked. If you look at the control word

with FSTCW, you will see that the default control word is 1370h,

instead of the 1332h returned by _control87. Also, if you send

_control87(0x00ff,0x00ff), this function will tell you that the

control word is set to 13FFh; however, FSTCW will reveal that the

control word is really set to 137Ch.

Because the run time depends on certain settings of the control word,

we do not want the run time to modify those settings. You can easily

write an assembly routine to set the control word to anything you

like using FLDCW. However, such a function would nullify all

subsequent calls to the floating-point run time.

For additional information on floating point exceptions, please refer

to the file FPEXCEPT.DOC contained in the C 5.1 package.

Additional reference words: 5.00 5.10 6.00 6.00a 6.00ax 7.00