About -lm switch used for linking math.h

K

Kaz Kylheku

not be in the spirit that say that inbuilt operators of the
language map to inbuilt operations of the processor, while
functions might combine such operations to form larger units.

I would say there is no such spirit.

The first implementations of C (well, B) generated "threaded" code.

``The B compiler on the PDP-7 did not generate machine instructions, but
instead `threaded code' [Bell 72], an interpretive scheme in which the
compiler's output consists of a sequence of addresses of code fragments that
perform the elementary operations. The operations typically—in particular for
B—act on a simple stack machine.''[1]

The need for run-time support routines just to have all the operators working
on all of the arithmetic types is more frequent than one might think; you don't
have to reach to examples like 8 bit micros. (Think: libgcc).
 
R

Richard Damon

Probably a more significant issue is that you can't actually do that
for C, because functions like printf() cannot easily be classified as
using, or not using, floating point, since the usage depends on the
format strings being passed in. So you'd usually get much of the FP
library since printf() *might* need it (and remember that on many
small machines, including many of the earlier ones, the FP library
included the emulation code for the basic FP operations).

One compiler I used ages ago, on a machine with no built in floating
point support, so there was a library that needed to be linked in if
your application used floating point, actually defined 2 versions of the
printf and related families. The version in the standard library did not
have support for floating point formats/numbers. A second version, with
the same name, was included in the floating point library which did
support the floating point types. Since the defined order of linking the
libraries was to check the floating point library first, (if the linker
was told you needed floating point), programs which used floating point
got the full printf function, while programs which did not use floating
point got the limited version of printf, and didn't get the "bloat" of
pulling in the floating point library.

It was possible to trick the compiler with things like unions to create
floating point values and then have printf fail to be able to print
them, since the program never needed "floating point math" so could link
without the floating point library. Of course the answer is that the
"conforming mode" requires linking in the floating point library, even
if not needed by the user code.
 
J

jacob navia

Le 28/01/12 19:58, Kaz Kylheku a écrit :
The need for run-time support routines just to have all the operators working
on all of the arithmetic types is more frequent than one might think; you don't
have to reach to examples like 8 bit micros. (Think: libgcc).

Adapting lcc-win for a customer beginning in March: no floating point,
no recursion, no dynamic memory (malloc): 16 bit processor.

More or less the same as I did for a 16 bit Analog Devices processor
some years ago.

Floating point will be supported in a HEAVY emulation layer.

There are quite a few jobs like this.
 
J

Joe keane

There was no difference between user-defined functions and built in
ines, and virtually every function could be implemented in C.

The advantage here is that the headers [and source if you have it] were
actual files that you can read, and they were written in something like
C, not APL, or some compiled binary form.
 
S

Stephen Sprunk

This is exactly the problem.

Denis Ritchie knew all about boolean types. They were excluded from C
for some reason, but trying to tack them on now causes all sorts of
problems and inconsistencies.

In C true is non-zero. But if we hash define true and false, if(2 ==
true) evaluates to false, if(2) evaluates to true. Most undesireable.

The logical solution to that problem would be to define an equality test
with a boolean operand so the test becomes if( (_Bool)2 == true).
Adding true as a keyword causes even more problems.

There's no need, though "#define true (_Bool)1" seems no less ugly than
"#define true _True". You couldn't add true itself as a keyword for the
same reason you can't add bool.

The main reason for a first-class boolean type would seem to be so that
you could redefine various operators to return a genuine boolean result
rather than an int.
Then if a _Bool is a one bit type, _Bool bit = 2; should set bit to
zero.

That's why a special rule is needed for conversions to _Bool.
Then we'd expect that _Bool myflags[100000000]; would be a space
efficient way of declaring a big array of flags. If instead you've got
to do unsigned char myflags[10000000/8], then you've got two boolean
types kicking about your program, and _Bool is a hinderance rather
than a help to anyone who's got to read your code.

Unfortunately, if you pack an array of _Bool like that, that causes all
sorts of problems when you try to take the address of one of the members
of the array.

Also, it would make accessing the members a lot more expensive than it
appears, which could well overshadow any performance benefit to packing
them.

S
 
8

88888 Dihedral

在 2012å¹´1月28日星期六UTC+8上åˆ12æ—¶42分44秒,Joe Pfeiffer写é“:
Are you really a computer literacy at all?

DOS was based upon CPM and X86 instructions and the shell part might have some features common to the unix in looks. DOS was not unix based at all.

DOS was more DEC VMS oriented in it's shell.
You're using a definition of "Unix-based" that is completely foreign to
just about everybody.

Unix is C-based from AT&T and the BSD free OS in charge except service feesand tape costs in universities to avoid the expectedlaw suites. But BSD lost the case in the court of not paying AT&T taxes. It was forbidden to upgrade for new versions bfore year 2000 of the BSD OS.

Anyway the linux part is better than BSD in the 386 era proved.

If the MMU and the heap walker in linux can catch up those from DEC experts then I would say unix is not a brain damaged OS at all.

Just test the malloc in the unix, then it is so lousy that it's better to do
one's own page swapping such as Windows OS.
 
I

Ian Collins

Then we'd expect that _Bool myflags[100000000]; would be a space
efficient way of declaring a big array of flags. If instead you've got
to do unsigned char myflags[10000000/8], then you've got two boolean
types kicking about your program, and _Bool is a hinderance rather
than a help to anyone who's got to read your code.

Unfortunately, if you pack an array of _Bool like that, that causes all
sorts of problems when you try to take the address of one of the members
of the array.

Also, it would make accessing the members a lot more expensive than it
appears, which could well overshadow any performance benefit to packing
them.

Which is one reason why C++ has specialised containers for bool. In
some ways bool sits better in C++ than in C (it has always been part of
the language), but then again just about every C project I've worked on
has some form of boolean type defined. So adding _Bool to the language
does follow the standardisation mantra of standardising existing practice.
 
K

Keith Thompson

Stephen Sprunk said:
The logical solution to that problem would be to define an equality test
with a boolean operand so the test becomes if( (_Bool)2 == true).

No, the logical solution is *not to compare Boolean values to true*.

"if (2)" isn't likely to occur in real code, but if you have a
variable like "ok" whose value is logically Boolean (whether it's
declared as bool, _Bool, int, or something else), then the way to
test it is simply:

if (ok) ...

Writing this:

if (ok == true) ...

make no more sense than this:

if ((ok == true) == true) ...

There are issues when you want to compare two non-constant Boolean
values to each other. For example, you might have two Boolean functions
that are supposed to compute the same result, and you want to verify
that they behave consistently. In that case, what you really want to do
is:

if (func1() == func2()) ...

which can fail if they return int, and one of them returns 1 while the
other returns 2 (both true values). In that case, you need some
additional logic to avoid that kind of problem -- such as:

if ((bool)func1() == (bool)func2()) ...

(assuming your compiler gets this right), or:

if (!!func1() == !!func2()) ...

But for most uses of _Bool, or bool, or even int used to hold logically
Boolean values, it's easy enough to write your code in a way that (a) is
straightforward, and (b) works correctly whether there are multiple true
values or not.

[...]
 
K

Keith Thompson

Malcolm McLean said:
Then we'd expect that _Bool myflags[100000000]; would be a space
efficient way of declaring a big array of flags. If instead you've got
to do unsigned char myflags[10000000/8], then you've got two boolean
types kicking about your program, and _Bool is a hinderance rather
than a help to anyone who's got to read your code.

Packing _Bool arrays would violate the general rule that objects other
than bit fields are at least one byte. Indexing such an array could not
be defined in terms of pointer arithmetic, as all other array indexing
is, because single bits are not addressable.

I've worked in other languages where you can declare packed arrays of
booleans (which works only because those languages don't define array
indexing in terms of lower-level constructs, and either don't let you
take the address of an element of a packed array or use fat pointers).

Adding such a feature to C is tempting, but I don't see how it could be
done without either breaking existing code, or adding an entirely new
feature to the language.
It is obviously good to have booleans documented as such. But in most
functions, you don't normally have many booleans, and they normally do
something quite simple, like adding or suppressing a newline on the
last line of output. For a small gain, _Bool causes too many
headaches, and that's neglecting the problem of double definition.

The pre-C99 treatment of booleans caused a great many headaches. IMHO,
the best way to avoid those headaches would have been to have "bool"
built into the language from the beginning. Since that didn't happen, I
think adding _Bool later on was the best compromise. But I acknowledge
that it was a compromise, and there are some drawbacks to it.
 
J

Joe Pfeiffer

Ben Bacarisse said:
I think you may be misremembering. The V6 manuals show that the C
library had no stdio, no malloc/free, no string handling... Most of
that arrived in V7. If the C library had been firmly in place by 1978,
I'd expect it to be documented in K&R, and it's not. It must have been
worked out (internally) by 1978 because it was mostly there when V7 came
out in 1979, but I suspect K&R saw it as just one of many possible
libraries for quite some time.

Taking a look at the V6 man pages, I am surprised by some of the things
that are indeed missing -- no malloc() (though there is an alloc(), and
there is a free()), no string handling. But while I don't find stdio by
that name, I do find printf(), putc(), fopen(), and related functions. I
also find abort(), atof(), and a host of other familiar names in Chapter
3.

Also, looking up cc in Chapter 1, one of the files linked in by default
is /lib/libc.a, which is described as "C library; see section III"

The V6 C reference manual does describe things like formatted output
(16.3), and states printf is available in "the C library".

I call all this "pretty firmly entrenched".

See http://wwwlehre.dhbw-stuttgart.de/~helbig/os/v6/doc/index.html
 
B

Ben Bacarisse

Joe Pfeiffer said:
Taking a look at the V6 man pages, I am surprised by some of the things
that are indeed missing -- no malloc() (though there is an alloc(), and
there is a free()), no string handling. But while I don't find stdio by
that name, I do find printf(), putc(), fopen(), and related functions.

There was no fopen as we know it. Not only was there no FILE interface
but there were separate function to open and to create a file.

Apart from there being no string functions, there was no ctype, setjmp,
signal, assert, gentenv, system... and so on.
I
also find abort(), atof(), and a host of other familiar names in Chapter
3.

You can also find a host of differences and missing functions. I
suppose it depends on what side of the question one is supporting.
Also, looking up cc in Chapter 1, one of the files linked in by default
is /lib/libc.a, which is described as "C library; see section III"

The V6 C reference manual does describe things like formatted output
(16.3), and states printf is available in "the C library".

There most certainly was, for each implementation, a C library. I hope
I did not suggest there wasn't. But to me, "the standard C library was
firmly in place" means that what was later to be the standard C library
was in place by Unix V6. That's not the case, by a long measure.

If all you meant was that there was a library, and that it was standard
"at the time" then that's not really saying much, but even that is
debatable. For example, I think that there was a "standard C library"
for GCOS that was not the same as the Unix one. They remained different
for a long time -- that's why ANSI C was such a success.
 
M

Malcolm McLean

Malcolm McLean said:
Then we'd expect that _Bool myflags[100000000]; would be a space
efficient way of declaring a big array of flags. If instead you've got
to do unsigned char myflags[10000000/8], then you've got two boolean
types kicking about your program, and _Bool is a hinderance rather
than a help to anyone who's got to read your code.

Packing _Bool arrays would violate the general rule that objects other
than bit fields are at least one byte.  Indexing such an array could not
be defined in terms of pointer arithmetic, as all other array indexing
is, because single bits are not addressable.
Exactly. If you need a space-efficient array of booleans, which might
not happen that often, but isn't such an uncommon thing to need, you
can't use _Bool, and there's no way of changing the semantics of _Bool
so that you can use it, without all sorts of knock-on effects
elsewhere in the language. (I once suggested that size_t be a double,
to accomodate bools and bitfields). But that limits the usefulness of
_Bool. It can't replace all booleans in every program.
 
N

Nick Keighley

If _Bool were simply an unsigned integer type with one value bit,
wouldn't the normal conversion rules mean (_Bool)2 == 0?  That's not how
_Bool works.

This is exactly the problem.

Denis Ritchie knew all about boolean types. They were excluded from C
for some reason, but trying to tack them on now causes all sorts of
problems and inconsistencies.

In C true is non-zero. But if we hash define true and false, if(2 ==
true) evaluates to false, if(2) evaluates to true. Most undesireable.
Adding true as a keyword causes even more problems.

Then if a _Bool is a one bit type, _Bool bit = 2; should set bit to
zero.

Then we'd expect that _Bool myflags[100000000]; would be a space
efficient way of declaring a big array of flags. If instead you've got
to do unsigned char myflags[10000000/8], then you've got two boolean
types kicking about your program, and _Bool is a hinderance rather
than a help to anyone who's got to read your code.

It is obviously good to have booleans documented as such. But in most
functions, you don't normally have many booleans, and they normally do
something quite simple, like adding or suppressing a newline on the
last line of output. For a small gain, _Bool causes too many
headaches, and that's neglecting the problem of double definition.

I like them for predicates, functions that return a bool result.
 
B

BartC

Keith Thompson said:
Malcolm McLean said:
Then we'd expect that _Bool myflags[100000000]; would be a space
efficient way of declaring a big array of flags. If instead you've got
to do unsigned char myflags[10000000/8], then you've got two boolean
types kicking about your program, and _Bool is a hinderance rather
than a help to anyone who's got to read your code.
I've worked in other languages where you can declare packed arrays of
booleans (which works only because those languages don't define array
indexing in terms of lower-level constructs, and either don't let you
take the address of an element of a packed array or use fat pointers).

Adding such a feature to C is tempting, but I don't see how it could be
done without either breaking existing code, or adding an entirely new
feature to the language.

Addressing a single bit means adding 3 extra bits or so to a pointer (when
there are no spare bits). I thought C could accommodate pointers of
different widths? The only problem then is that void pointers would need to
be bit-pointer compatible, making them inefficient wherever bit-addressing
is not needed.

Alternatively, bit-pointers can be a special case which cannot be converted
fully to and from conventional pointers. Either it's not allowed at all, or
some information might be lost.
 
N

Nick Keighley

[...] but then again just about every C project I've worked on
has some form of boolean type defined.

I even knew of a project that had four different boolean types. One of
which had TRUE, FALSE and MAYBE.
 
M

Malcolm McLean

Addressing a single bit means adding 3 extra bits or so to a pointer (when
there are no spare bits). I thought C could accommodate pointers of
different widths? The only problem then is that void pointers would need to
be bit-pointer compatible, making them inefficient wherever bit-addressing
is not needed.
It's not really a problem on 64 bit systems. Computers which use all
64 bits of address space won't be commonly available for quite some
time (about 48 years, assuming Moore's law is correct, and that a
present day computer uses all of 32 bits). So we can put the extra bit
index bits in a normal width pointer.
 
S

Stefan Ram

Nick Keighley said:
I like them for predicates, functions that return a bool result.

I believe the C common style is to code, for example,

int is_visible( int const i ){ return i &( 1 << 7 ); }

(assume that bit #7 is a »visible« flag.

. This can be used in

if( is_visible( k ))show( k );

with no problems. I believe the reason for this is that

int is_visible( int const i ){ return !!( i &( 1 << 7 )); }

would take more time for additional operations (even when
I assume that »!!« is being optimized by the compiler),
which are not always needed.

If a normalized value is needed in special cases,
the caller still is free to use »!!is_visible( arg )«.

I believe that C coding is more hard than coding in Perl.
But C is faster than Perl. So, one chooses to use C, when
execution speed is crucial. Therefore, it seems to me that
an execution-speed aware programming style is more adopted
to the C language.
 
S

Stefan Ram

(assume that bit #7 is a »visible« flag.

) - That line was intended to be:

»(assumING that bit #7 is a »visible« flag.)«
int is_visible( int const i ){ return !!( i &( 1 << 7 )); }
would take more time for additional operations (even when
I assume that »!!« is being optimized by the compiler),
which are not always needed.

Ok, when a call to the above function is being inlined,
then, in

if( is_visible( k ))...

a compiler can optimize »!!« to the point where it effectively
has no overhead.
 
J

Joe keane

Early and small microprocessors (the 6502 is still
manufactured today!) also do not have »number crunchers«, so
that a C with double isn't just a small layer that make the
processor's operations available via operations in a
portable language on these processors, but it needs a
library even for the floating point operators, which might
not be in the spirit that say that inbuilt operators of the
language map to inbuilt operations of the processor, while
functions might combine such operations to form larger units.

I doubt the fact that some machines don't have number crunchers escaped
Dennis Ritchie.

So we have two choices, make everyone use functions for floating-point
operations, or stray a bit from the tightness of operations to machine
operations, in the case of missing number cruncher. The first would be
pretty awkward [i.e., worse than FORTRAN].

There's also the case where there *are* instructions for such things;
they just trap and leave some code to figure out what to do.

Also if it you know that the target doesn't have floating-point support,
you'd probably do something else (home-brew fixed-point). No need to get
exact 754 semantics, if you don't need it.

But he didn't extend it to user-defined types.
 
K

Keith Thompson

BartC said:
Keith Thompson said:
Malcolm McLean said:
Then we'd expect that _Bool myflags[100000000]; would be a space
efficient way of declaring a big array of flags. If instead you've got
to do unsigned char myflags[10000000/8], then you've got two boolean
types kicking about your program, and _Bool is a hinderance rather
than a help to anyone who's got to read your code.
I've worked in other languages where you can declare packed arrays of
booleans (which works only because those languages don't define array
indexing in terms of lower-level constructs, and either don't let you
take the address of an element of a packed array or use fat pointers).

Adding such a feature to C is tempting, but I don't see how it could be
done without either breaking existing code, or adding an entirely new
feature to the language.

Addressing a single bit means adding 3 extra bits or so to a pointer
(when there are no spare bits). I thought C could accommodate pointers
of different widths? The only problem then is that void pointers would
need to be bit-pointer compatible, making them inefficient wherever
bit-addressing is not needed.

C can accommodate pointers of different widths, but it can't accomodate
pointers to units smaller than CHAR_BIT bits (i.e., at least 8 bits).
Alternatively, bit-pointers can be a special case which cannot be
converted fully to and from conventional pointers. Either it's not
allowed at all, or some information might be lost.

Yes, as I said, if you don't want to break existing code (by
violating existing guarantees about pointers), you'd need a new
language feature.

I can imagine ways to do it. A *bit-pointer* could be a new kind
of scalar, incompatible with pointers but convertible to and from
them in some restricted cases. (The name is not intended to imply
that a bit-pointer is a kind of pointer; perhaps a different name
would be clearer, but I can't think of a good one.) Indexing of
bit arrays could be defined in terms of arithmetic on bit-pointers,
not on pointers. Conversion of a bit-pointer to void* either would
not be permitted or would lose information, yielding a pointer to
the containing byte.

You could either invent a new syntax for bit-pointer operations,
including indexing, or you could overload the existing syntax,
with the semantics depending on whether the operands are pointers
or bit-pointers. I'm not sure which would be more confusing.

But given the lack of existing practice and the sparse demand for
this kind of thing, I don't believe it will happen. The most likely
way to get it into C would be to implement it in a popular compiler
and push for the committee to add it to C202X.

(Interestingly, this article is the only reference I can find to
"C202X" referring to the next C standard, though apparently there's
a mutation by that name.)
 

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

Forum statistics

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

Latest Threads

Top