Floating types are defined by §5.2.4.2.2 of the C standard (draft N1570 at least):
The characteristics of floating types are defined in terms of a model that describes a representation of floating-point numbers and values that provide information about an implementation’s floating-point arithmetic.21) The following parameters are used to define the model for each floating-point type:
s
sign (±1)
b
base or radix of exponent representation (an integer > 1)
e
exponent (an integer between a minimum emin and a maximum emax)
p
precision (the number of base-b digits in the significand)
fk
nonnegative integers less than b (the significand digits)
A floating-point number (x) is defined by the following model:

So yes, that expression is somewhat safe, except in the case where foo
returned one of the "other kinds of floating point numbers" not specified by the standard:
In addition to normalized floating-point numbers ( f1 > 0 if x ≠ 0), floating types may be able to contain other kinds of floating-point numbers, such as subnormal floating-point numbers (x ≠ 0, e = emin, f1 = 0) and unnormalized floating-point numbers (x ≠ 0, e > emin, f1 = 0), and values that are not floating-point numbers, such as infinities and NaNs.
and:
An implementation may give zero and values that are not floating-point numbers (such as infinities and NaNs) a sign or may leave them unsigned.
There are probably other caveats to this, but the standard goes in a fair bit of details about the characteristics of these types. You can read all about them in this publicly available draft.