Floating point linkage

C

C learner

Point out the error in the following program.

#include<stdio.h>
int main()
{
struct emp
{
char name[20];
float sal;
};
struct emp e[10];
int i;
for(i=0; i<=9; i++)
scanf("%s %f", e.name, &e.sal);
return 0;
}
[A]. Suspicious pointer conversion
.
Floating point formats not linked (Run time error) @
[C]. Cannot use scanf() for structures
[D]. Strings cannot be nested inside structures


Answere is B






My question is what is Floatin point linkage and how it is applicable here.
Please elaborate.
 
B

Ben Bacarisse

C learner said:
Point out the error in the following program.

#include<stdio.h>
int main()
{
struct emp
{
char name[20];
float sal;
};
struct emp e[10];
int i;
for(i=0; i<=9; i++)
scanf("%s %f", e.name, &e.sal);
return 0;
}
[A]. Suspicious pointer conversion
.
Floating point formats not linked (Run time error) @
[C]. Cannot use scanf() for structures
[D]. Strings cannot be nested inside structures


Answere is B


But that answer is wrong because it is not an error in the program. It
may be that a system gives such an error, but it does not reflect any
problem with the program itself.

The program does have an error (ignoring the fact it does nothing). The
%s format can overflow the char array e.name. The format should be
%19s.

<snip>
 
K

Kenny McCormack

Ben Bacarisse said:
But that answer is wrong because it is not an error in the program. It
may be that a system gives such an error, but it does not reflect any
problem with the program itself.

Not if you, as a sensible person would, consider "the program" to be the
entire edit/compile/run cycle. Obviously, there's a problem somewhere.
The program does have an error (ignoring the fact it does nothing). The
%s format can overflow the char array e.name. The format should be
%19s.


On your logic, you would say that that is not an error in the program, but
rather a user error (supplying bad input - should be on the head of the
user, not the program).
 
R

Rob

Point out the error in the following program.
[snip]

scanf("%s %f", e.name, &e.sal);




The problem that I see is that an ampersand (&) is missing in
front of the first variable.
 
K

Keith Thompson

Rob said:
Point out the error in the following program.
[snip]

scanf("%s %f", e.name, &e.sal);



The problem that I see is that an ampersand (&) is missing in
front of the first variable.


Nope. e.name is of type char[20], which decays to char* in that
context, so no & is necessary (and in fact adding an & would cause the
argument to be of the wrong type).

Which would have been more obvious if you'd quoted more of the code.
 
G

glen herrmannsfeldt

C learner said:
Point out the error in the following program.
#include<stdio.h>
int main()
{
struct emp
{
char name[20];
float sal;
};
struct emp e[10];
int i;
for(i=0; i<=9; i++)
scanf("%s %f", e.name, &e.sal);
return 0;
}
[A]. Suspicious pointer conversion
.
Floating point formats not linked (Run time error) @
[C]. Cannot use scanf() for structures
[D]. Strings cannot be nested inside structures


My answer would be "Don't use floating point for monetary values."

I believe it was Knuth you said that finance and typesetting should
be done in fixed point (not long after he worked on TeX).

(snip)
My question is what is Floatin point linkage and how it is
applicable here. Please elaborate.

I don't see that anyone answered this yet.

In the early days of the 8086 and 8088 (if not other processors)
floating point operations were done by software subroutine calls.

I am not sure now the exact case, but if no actual floating point
operations were done, the routines needed to do floating point
calculations weren't linked in. (That was before the 8087, or at
least before it was popular.) The routines were big enough, and
computers small enough, that it was worthwhile to not link them if
not needed. Compilers didn't look inside the format string for
scanf() and printf() (and associated calls). If the only floating
point operations were those done by the I/O conversion routines,
the floating point library wasn't there, and they would fail with
the indicated message.

One fix would be to do some actual floating point operation,
even if not actually needed.

-- glen
 
R

Rob

Nope. e.name is of type char[20], which decays to char* in that
context, so no & is necessary (and in fact adding an & would cause the
argument to be of the wrong type).

Which would have been more obvious if you'd quoted more of the code.


You are totally right. Thank you for the correction.

This is why I lurk here most of the time. :)
 
Ö

Öö Tiib

One fix would be to do some actual floating point operation,
even if not actually needed.

It seems that this is already floating point operation (unary minus):

const float minus_one = -1.0f;

Rationale is that there are no negative floating constants in C by
(6.4.4.2). Is it actually enough?
 
G

glen herrmannsfeldt

It seems that this is already floating point operation (unary minus):
const float minus_one = -1.0f;
Rationale is that there are no negative floating constants in C by
(6.4.4.2). Is it actually enough?

Maybe not. The languages is defined that way, but as well as I
know, all compilers will generate a negative constant. Many will do
a lot more with constant expressions.

When the Pentium FDIV bug was discovered, there were C source
programs to demonstrate it by dividing two constants. Many compilers
would evaluate the constant expression at compile time using software
emulated floating point, and so not actually use FDIV at all.

As optimizers get better, it is harder to generate something that
is guaranteed not to happen at compile time. How about:

float one,two;
sscanf("1.0",&one);
two=one+one;

-- glen
 
K

Keith Thompson

Öö Tiib said:
It seems that this is already floating point operation (unary minus):

const float minus_one = -1.0f;

Rationale is that there are no negative floating constants in C by
(6.4.4.2). Is it actually enough?

It depends on the compiler, but probably not.

As far as the language is concerned, the value 1.0f has the unary "-"
operator applied to it. But any compiler worth what you paid for
it (even if it's free) will evaluate the negation at compile time,
which would most likely bypass the compiler's check for whether
the floating-point implementation needs to be linked.

The compiler in question is *already* violating the C standard by
not handling conforming code correctly (by applying an optimization
in cases where it's incorrect to do so). We can't rely on the
standard to tell us how it will behave.
 
S

Stephen Sprunk

I don't see that anyone answered this yet.

In the early days of the 8086 and 8088 (if not other processors)
floating point operations were done by software subroutine calls.

I am not sure now the exact case, but if no actual floating point
operations were done, the routines needed to do floating point
calculations weren't linked in. (That was before the 8087, or at
least before it was popular.) The routines were big enough, and
computers small enough, that it was worthwhile to not link them if
not needed. Compilers didn't look inside the format string for
scanf() and printf() (and associated calls). If the only floating
point operations were those done by the I/O conversion routines,
the floating point library wasn't there, and they would fail with
the indicated message.

Note that even though printf() and scanf() used floating-point
operations themselves, a "clever" optimization prevented FP support from
being linked in to every program that used stdio. The assumption was
that if you didn't explicitly call any FP functions in your own code,
then the FP parts of the stdio code wouldn't get used. The example code
here violates that assumption, hence the linker error.

That this situation persists to this day, though, is surprising; given
all the other junk that gets linked in by default, the prevalence of
hardware FP support, ubiquitous dynamic shared libraries and explosive
growth in available memory, it seems like this optimization has long
outlived its usefulness.

S
 
G

glen herrmannsfeldt

(snip, I wrote)
(snip)
Note that even though printf() and scanf() used floating-point
operations themselves, a "clever" optimization prevented FP
support fromeing linked in to every program that used stdio.
The assumption was that if you didn't explicitly call any FP
functions in your own code, then the FP parts of the stdio
code wouldn't get used. The example code here violates that
assumption, hence the linker error.

I am not sure exactly how it was implemented. The IBM OS/360
linker has weak external references that will be resolved if the
called routine is linked, but won't pull a routine from a library.
I don't remember which linkers provide that feature.
That this situation persists to this day, though, is surprising;
given all the other junk that gets linked in by default,
the prevalence of hardware FP support, ubiquitous dynamic
shared libraries and explosive growth in available memory,
it seems like this optimization has long outlived its usefulness.

Yes, but old compilers might still run on currently available systems.
I believe 16 bit DOS/Windows code will run on XP.

Now, why is it that we still need -lm to link the math library
on unix and unix-like systems? Why not just put them into
the same library with the rest of libc?

-- glen
 
T

Thomas Jahns

Now, why is it that we still need -lm to link the math library
on unix and unix-like systems? Why not just put them into
the same library with the rest of libc?

I'd say typically because

- libm doesn't have to be dynamically linked (for libc there's no static version
on many platforms)

- it makes sense to replace libm with something having the same ABI but extended
precision/error checking/whatnot without any change to libc functions

Regards, Thomas
 
S

Stephen Sprunk

I'd say typically because

- libm doesn't have to be dynamically linked (for libc there's no
static version on many platforms)

Since (nearly) every program (and other library) on a typical Unix
platform is going to be linked to libc by default, it would be utterly
wasteful to statically link against it. libc is the canonical example
of why dynamic linking is needed.

In contrast, few programs (and other libraries) use libm, so while
static linking would probably still be wasteful, it'd be a relatively
minor problem in practice.
- it makes sense to replace libm with something having the same ABI
but extended precision/error checking/whatnot without any change to
libc functions

IIRC, if you explicitly link to your own library, that will override the
functions in libc, so that option wouldn't be lost by including the math
functions in libc.

(It would still be wise to provide an empty libm, to avoid causing
unnecessary linking problems for builds that assume they need it.)

S
 
S

Seebs

Since (nearly) every program (and other library) on a typical Unix
platform is going to be linked to libc by default, it would be utterly
wasteful to statically link against it. libc is the canonical example
of why dynamic linking is needed.

I feel I should point out a distinction, at some risk of going off-topic:

Dynamic and static linking are NOT the same question as shared or unshared.

At least one operating system I know of implemented static linking for
shared libraries like libc, so you could get a noticeable speed improvement
over a typical dynamic linker, but still have the massive address space
savings of letting multiple programs use the same blocks of memory for the
shared text segments.

-s
 
S

Stephen Sprunk

I am not sure exactly how it was implemented. The IBM OS/360 linker
has weak external references that will be resolved if the called
routine is linked, but won't pull a routine from a library. I don't
remember which linkers provide that feature.

Ah. I wasn't sure how it was implemented either, but it's a common
enough complaint that I remember the general issue.
Yes, but old compilers might still run on currently available
systems. I believe 16 bit DOS/Windows code will run on XP.

64-bit Windows dropped support for DOS/Win16 code.

It's not just "old" compilers, though; modern 64-bit tool chains have
inherited the same "feature".
Now, why is it that we still need -lm to link the math library on
unix and unix-like systems? Why not just put them into the same
library with the rest of libc?

That's what I said above :)

S
 
S

Stephen Sprunk

I feel I should point out a distinction, at some risk of going
off-topic:

Dynamic and static linking are NOT the same question as shared or
unshared.

At least one operating system I know of implemented static linking
for shared libraries like libc, so you could get a noticeable speed
improvement over a typical dynamic linker, but still have the massive
address space savings of letting multiple programs use the same
blocks of memory for the shared text segments.

How is that even possible? When you statically link a library, the
parts that you need are added to your executable and the rest is thrown
away, and even the parts that are included are subject to link-time
relocation, so they can't be shared with other programs.

S
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top