Does C really now that little?

M

Martin Marcher

Hi,

I've read several questions and often the answer was

'C knows nothing about [lots of different stuff here].'

So if C knows that little as some people say, what are the benefits, I
mean do other languages know more or is it a benefit that C knows nearly
nothing (what I can think about is that C is the largest common divisor
defined on most available platforms)?

This question came to my mind when I was reading "Serial Number of the
Hard Drive" (Message ID: [email protected]).
Because I often read 'Unix is written in C' I'm asking myself how an OS
can be written in C if it knows nothing about anything.

And please stay on the newbiest level possible so I can understand that or
just tell me to wait 'till I learned more :)

thx
Martin
 
T

Thomas Matthews

Martin said:
Hi,

I've read several questions and often the answer was

'C knows nothing about [lots of different stuff here].'

So if C knows that little as some people say, what are the benefits, I
mean do other languages know more or is it a benefit that C knows nearly
nothing (what I can think about is that C is the largest common divisor
defined on most available platforms)?

This question came to my mind when I was reading "Serial Number of the
Hard Drive" (Message ID: [email protected]).
Because I often read 'Unix is written in C' I'm asking myself how an OS
can be written in C if it knows nothing about anything.

And please stay on the newbiest level possible so I can understand that or
just tell me to wait 'till I learned more :)

thx
Martin

The issue is that there is a finite set of functionality in the
language. Users are allowed to augment that functionality, but it
won't be discussed in this newsgroup.

The Unix operating system was written using the C language, along
with a whole bunch of platform specific code. The code that is
platform specific won't be discussed here.

There is nothing wrong with you writing a program that uses
platform extensions to read the serial number or other harddisk
information. Since the issue is not in the domain of the C language,
it won't be discussed here.

Also be aware that if the issue is not in the domain of the
standard C language, it may not exist on all platforms.
 
M

Mike Wahler

Martin Marcher said:
Hi,

I've read several questions and often the answer was

'C knows nothing about [lots of different stuff here].'

So if C knows that little as some people say, what are the benefits, I
mean do other languages know more or is it a benefit that C knows nearly
nothing (what I can think about is that C is the largest common divisor
defined on most available platforms)?

I'd call it 'lowest common denominator' (in context of
'well-established' high level languages).

A major design goal of (standard) C was platform-independence.
So the committee defined a 'minimal' 'abstract machine' to
host a C program, which only contains the minimum 'components'
of a computer system (e.g. data storage, arithmetic, logic,
control flow, external data storage (via 'streams'), etc).

This allows it to include many types of systems, from e.g.
a chip embedded in an automobile engine, to desktop PCs.
Those systems that have 'additional' features (such as printers,
directory systems etc.) typically have nonstandard, machine-
specific code (written in whatever language) for them that offers
an interface with C. This code should be described in the
documentation for a specific C implementaion and/or operating
system.
This question came to my mind when I was reading "Serial Number of the
Hard Drive" (Message ID: [email protected]).
Because I often read 'Unix is written in C' I'm asking myself how an OS
can be written in C if it knows nothing about anything.

Unix cannot fully be implemented using only standard C.
Machine-specific knowledge is needed. Also note that
when Unix was created, C had not yet been standardized.
And please stay on the newbiest level possible so I can understand that or
just tell me to wait 'till I learned more :)

I hope my explanation helped.

-Mike
 
L

Lew Pitcher

Martin said:
Hi,

I've read several questions and often the answer was

'C knows nothing about [lots of different stuff here].'

So if C knows that little as some people say, what are the benefits, I
mean do other languages know more or is it a benefit that C knows nearly
nothing (what I can think about is that C is the largest common divisor
defined on most available platforms)?

This question came to my mind when I was reading "Serial Number of the
Hard Drive" (Message ID: [email protected]).
Because I often read 'Unix is written in C' I'm asking myself how an OS
can be written in C if it knows nothing about anything.

And please stay on the newbiest level possible so I can understand that or
just tell me to wait 'till I learned more :)


There's C and there's /C/.

Standard C (the topic of discussion here in comp.lang.c) is defined such
that it offers the same facilities no matter where it is used. These minimum
facilities are enough to build fairly comprehensive applications, although
not necessarily operating systems or device drivers.

However, with a little additional "glue" (in the form of external add-on
libraries), you can extend C such that it /can/ be used to write operating
systems and device drivers. For operating systems, the glue commonly
consists of a handfull of Assembly language modules that provide a
consistant interface to the hardware. For device drivers, the "glue"
consists of libraries or modules that provide a consistant interface to the
operating system.

In theory, with the proper hardware, it should be possible to write an
operating system with Standard C. In practice, it's not as simple as all that.

In comp.lang.c, we discuss the C as in "Standard C" that can be used to
create applications that are platform-independant. The other C, the C that
requires platform-specific extensions, is left to other groups to discuss.


--

Lew Pitcher, IT Consultant, Application Architecture
Enterprise Technology Solutions, TD Bank Financial Group

(Opinions expressed here are my own, not my employer's)
 
D

Dan Pop

In said:
I've read several questions and often the answer was

'C knows nothing about [lots of different stuff here].'

Which should be read as: ``the C language specification doesn't mention
anything about [lots of different stuff here]''.
So if C knows that little as some people say, what are the benefits, I
mean do other languages know more or is it a benefit that C knows nearly
nothing (what I can think about is that C is the largest common divisor
defined on most available platforms)?

If you can restrict your code to what the C "knows about", it will be
usable on any platform with a C compiler. It is true that other languages
know more, but it is equally true that they cannot be implemented on as
many platforms as C (at least, without a significant loss of efficiency).

Another reason C knows so little is that the people who wrote the language
specification didn't bother to put more into it. As a result, even
things that could be efficiently implemented practically everywhere are
missing from the language specification, the usual excuse being that
they've been left for other standards to define. But those other
standards are not as widely implemented as the C standard, so plenty of
things that are needed on practically every platform need to be coded in
a platform-specific way.
This question came to my mind when I was reading "Serial Number of the
Hard Drive" (Message ID: [email protected]).
Because I often read 'Unix is written in C' I'm asking myself how an OS
can be written in C if it knows nothing about anything.

Nobody has implemented any OS using only the features of C fully specified
by the language specification. As a result, there is no OS that can be
used on *any* platform with a C implementation.

OTOH, C programming is not limited to the features fully specified by the
language specification. Each implementation completes certains parts that
are only partly specified by the language definition (the implementation
defined features) and also adds its own extensions to the language
(and library) specification. People who write OSs in C make heavy use
of these extra features. But even with these extra features, certain
(usually small) parts of the OS still have to be written in assembly.

As a concrete example, C knows nothing about directories. Yet, it is
perfectly possible to write a C program that lists the contents of a
directory on any platform supporting the concept of directory (i.e.
practically on any hosted platform).
And please stay on the newbiest level possible so I can understand that or
just tell me to wait 'till I learned more :)

The thing you need to understand is that this newsgroup decided to focus
only on the parts of C that are specified by the language definition,
leaving the discussion about platform-specific extensions to
platform-specific newsgroups.

The big advantage of this approach, from the newbie's point of view
is that, by reading the newsgroup, he gets a clear idea about what
is a standard C feature and what is an extension. This helps a lot
when having to write portable C code (even if parts of the application
will have to be written in non-portable C).

The advantage for the more experienced programmer is that, by reading
this newsgroup and the newsgroup dedicated to programming on his platform,
he doesn't have to waste any time with questions and answers about C
programming on other platforms, about which he couldn't care less.

Dan
 
M

Martin Marcher

The issue is that there is a finite set of functionality in the language.

My question was more like, why it is that C knows so little (since you
didn't answer me I allow myself to asume that C really knows very little).
Users are allowed to augment that functionality, but it won't be discussed
in this newsgroup.

Problem 1: The only one that can forbid or allow me aksing questions is my
mother

Problem 2: If you would be so kind to point me to a group where I can ask
that question (I didn't find a group called
comp.lang.c.historical-background or similiar)

Problem 3: Please tell me the reason why asking this question is OT in
this group, maybe the question came thru the wrong way but to me it
sounded much like a question about ANSI C, tough it is more general than
why this or that code doesn't react like expected.
The Unix operating system was written using the C language, along with a

You repeat what I said.
whole bunch of platform specific code. The code that is platform specific
won't be discussed here.

I didn't ask anything about that code.
There is nothing wrong with you writing a program that uses platform
extensions to read the serial number or other harddisk information. Since
the issue is not in the domain of the C language, it won't be discussed
here.

If you would have had a look at the post I mention in my original post you
would have seen that I didn't ask the question, so you don't need to tell
me not to discuss platform specific code, I'm really new to C and did my
best to stay standard conform, also if you search my previous posts I
mentioned everytime I wasn't sure wether it was ANSI C or not, so people
that strictly refer to ANSI C aren't forced to read further. A simple 'ask
at this group' would be enough

greets
Martin

PS: in case you want to flame use my mail address because flames are
off-topic and users are not allowed to do this in the newsgroup
 
M

Martin Marcher

Hi,

I think the 'abstract machine' Mike Wahler mentioned was the missing link
in my brain to get the point of it. I thought that it was just some 'per
definition we say that it is this way'-stuff, but couldn't think of what
kind of definition the people defining the standard were thinking about,
especially since I never thought that access to directories could be
outside of the standard, which makes the mentioned 'abstract machine'
really minimal

thx all
Martin
 
E

Eric Sosman

Mike said:
I'd call it 'lowest common denominator' (in context of
'well-established' high level languages).

Topic drift: Why do people so often say "lowest (or
least) common denominator" when they mean "greatest common
denominator?"

ObOnTopicCodeSample:

/* least_common_denominator() calculates and returns
* the least common denominator of two unsigned integers,
* using an algorithm attributed to A.E. Neumann.
*/
unsigned int least_common_denominator(
unsigned int u, unsigned int v)
{
return 1;
}
 
D

Default User

Martin said:
Problem 1: The only one that can forbid or allow me aksing questions is my
mother


Turns out you're wrong about that.

*plonk*




Brian Rodenborn
 
A

Arthur J. O'Dwyer

My question was more like, why it is that C knows so little (since you
didn't answer me I allow myself to asume that C really knows very little).

Or that C doesn't specify lots of things [OS stuff, sound, graphics,
.... basically anything having to do with time and space instead of
algorithms].
Problem 1: The only one that can forbid or allow me aksing questions is my
mother

Hey, now. Thomas didn't say your question was OT; he said that while
users are allowed to augment C's functionality, we don't discuss that
here. IOW, it's fine to ask what C does and doesn't have. It's just
not okay to ask specifically *about* things that C doesn't have.
Like, don't ask, "How do I make pictures in C?" or "How do I tell if
the Shift key is being pressed?" because those aren't things that C
can do [portably].
Problem 2: If you would be so kind to point me to a group where I can ask
that question (I didn't find a group called
comp.lang.c.historical-background or similiar)

Here is fine.
Problem 3: Please tell me the reason why asking this question is OT in
this group, maybe the question came thru the wrong way but to me it
sounded much like a question about ANSI C, [though] it is more general
than why this or that code doesn't react like expected.

Your question was on-topic. And the answer to your question is,
"Yes, C doesn't know much. And the stuff that C doesn't know is
off-topic."
You repeat what I said.


I didn't ask anything about that code.

Then it is not the case that your question won't be discussed here.
If you would have had a look at the post I mention in my original post you
would have seen that I didn't ask the question, so you don't need to tell
me not to discuss platform specific code,

Heck, if you already *knew* not to discuss platform-specific code,
then wouldn't you have read the FAQ, or even a couple pages of the
Standard, already? Then you wouldn't have needed to ask the question
you *did* ask. [Not trying to be harsh; just pointing out the
obvious - people who don't know much about C and post here usually
need the reminder that execl() or RunWindows() aren't standard C.]

HTH,
-Arthur
 
A

Arthur J. O'Dwyer

Topic drift: Why do people so often say "lowest (or
least) common denominator" when they mean "greatest common
denominator?"

Bzzt. You mean "greatest common divisor," a la Euclid.
The "lowest common denominator" phrase refers to fractions,
where the LCD of 3/7 and 2/3 is 21, for example.

"Lowest common denominator," involving as it does the
words "low" and "common," is much more popular as a
pejorative, at least on this side of the pond - e.g.,
"Temptation Island" is a TV show appealing to the "lowest
common denominator" in TV audiences.

Saying C is the "greatest common divisor" among languages
just sounds weird to me. ;-)

-Arthur
 
L

Larry Doolittle

However, with a little additional "glue" (in the form of external add-on
libraries), you can extend C such that it /can/ be used to write operating
systems and device drivers. For operating systems, the glue commonly
consists of a handfull of Assembly language modules that provide a
consistant interface to the hardware.

Without distracting from the conceptual message, let me
modify a detail. On many computers, much interesting
interaction with the hardware happens by reading and writing
special memory locations. C gives a perfectly clean syntax
for that, using volatile <type>* pointers.

So for instance, an operating system that needed to know if some
hypothetical Ethernet chip had received any new packets could

int packet_cnt;
volatile int *packet_cnt_reg = (volatile int *)0xe7000010;
if ((packet_cnt = *packet_cnt_reg) != 0) {
/* receive a packet */
}

No assembly required. ;-)
And indeed, OS writers use this technique whenever possible, for the
obvious readability and portability-across-architectures advantages
over assembly.
In theory, with the proper hardware, it should be possible to write an
operating system with Standard C.

Maybe the above concept is what you were referring to.
But when people bring it up on comp.lang.c, they are
chased away because such "wild" pointer dereferencing
triggers "undefined behavior".

- Larry
 
R

Richard Heathfield

Eric Sosman wrote:

ObOnTopicCodeSample:

/* least_common_denominator() calculates and returns
* the least common denominator of two unsigned integers,
* using an algorithm attributed to A.E. Neumann.
*/
unsigned int least_common_denominator(
unsigned int u, unsigned int v)
{
return 1;
}

I disagree that 1 is the least common denominator. It's extremely common.
 
R

Richard Heathfield

Martin said:
Hi,

I've read several questions and often the answer was

'C knows nothing about [lots of different stuff here].'

This is a "cutesy" way of saying "to do <foo> requires
implementation-specific extensions which are not available on all
implementation and, even on those implementation where they are available,
the way in which those extensions are used is very likely to differ from
one implementation to another".
So if C knows that little as some people say, what are the benefits,

Portability /and/ power. If you modularise your code so that all the
portable code is separate from the non-portable code, you can move the code
from one implementation to another with a minimum of effort, because you
only have to re-write the non-portable bit. On one project I worked on - a
browser for embedded systems - a mere 1% of 500,000 lines of code was
non-portable. To move to a new platform (which this company did on a
regular basis), the team needed only to rewrite 5,000 lines of code, all of
which were isolated into a few core modules for easy identification.
I
mean do other languages know more or is it a benefit that C knows nearly
nothing (what I can think about is that C is the largest common divisor
defined on most available platforms)?

Languages that are only implemented on one platform can take that platform's
features for granted. Those that are not, can't. That doesn't mean you lose
any power, though, because you can use an implementation's extensions to
gain access to that platform's features. If you do this thoughtfully and
carefully, the portability cost can be very low indeed.
 
S

Scott McPhillips

Martin said:
especially since I never thought that access to directories could be
outside of the standard, which makes the mentioned 'abstract machine'
really minimal

Then your awareness of the application domain is sharply limited.
Millions of machines that do not have disks or disk directories have
been programmed in C. For example: microwave ovens, hotel room locks,
cell phones, ...
 
R

Richard Delorme

Scott McPhillips a écrit :
Then your awareness of the application domain is sharply limited.
Millions of machines that do not have disks or disk directories have
been programmed in C. For example: microwave ovens, hotel room locks,
cell phones, ...

This is not a problem of having discs or not. C supports files through
functions like rename(), remove(),... Then, why are directories, which are
useful at keeping files well ordered, not part of the language?
Why that feature is in, and why this one is out? Why complex numbers are
supported in C99? How many applications need complex numbers? And why not
matrix algebra then? The C language already supports two level of
compliance for freestanding or hosted environment. Why not adding another
level, called "graphical environment", with graphical functions added into
the standard libraries?
I don't think there is any rationale here. It probably just depends on the
people attending the commitee meetings and their particular needs.
 
C

Chris Torek

This is not a problem of having discs or not. C supports files through
functions like rename(), remove(),... Then, why are directories, which are
useful at keeping files well ordered, not part of the language? ...
I don't think there is any rationale here. It probably just depends on the
people attending the commitee meetings and their particular needs.

It is certainly true that C is a creation of humans, and humans
are rarely consistent or logical. Thus, we should not expect C to
be all that consistent and logical. :) (Nonetheless, many people
*do* seem to expect it, perhaps because C is "pretty consistent
and logical", at least when compared to so many other languages.)

In this particular case, however, I think we should observe that
the original C standardization effort included folks from the
mainframe world, where people use operating systems like Univac's
EXEC-8 and IBM's MVS and TSS.

One of the interesting aspects of these OSes is that they do not
*have* directories. They *do* have files, and file names may appear
in "file catalogues", which are very much *like* directories; or
perhaps in "data sets" or "partitions" or other directory-like
concepts. But if one sits down with a set of "directory operations"
-- "what would we like to be able to do with a directory facility
in a C-like language" -- and tries to apply it to these systems,
it comes up short every time.

Interestingly, however, if one does this with ordinary files, it
likewise comes up short. These mainframes have more file types
than you can shake a Microsoft Product at, and portable C cannot
deal with those either. So why are any files at all available in
C, yet directories are not?

Of course, only those who were on the X3J11 (ANSI C) committee in
the 1980s could really answer this, but we have some very strong
hints available in the C89 Rationale, and in the charter that the
X3J11 committee had in the first place: to standardize existing
practice, without inventing new practice. K&R C's <stdio.h> and
associated functions were in fact in use on these mainframes; stdin
and stdout worked, and fopen()ing files gave some minimal functionality.
But K&R C had no standard directory operations: there was no
<dir.h> or <dirent.h>, no opendir() function, no scandir(); indeed,
all of the various functions that are rather common today were rare
at the time. In short, there was no existing practice to standardize.

(Not that this stopped the X3J11 folks in all cases. For instance,
they stole "const" from C++, and broke it. :) They also picked
the wrong rules for dealing with narrow unsigned arithmetic, where
the Unix compilers got it right but one particular PC compiler used
the silly "value-preserving" rules. They even tried to add an
11th-hour unworkable version of C99's "restrict", called "noalias".
But for whatever reason, they did not invent directory operations.)
 
K

Kevin Easton

Ben Pfaff said:
Because they do mean least common denominator. If I am adding
1/3 to 1/2, then the LCD is 6: 1/3 + 1/2 = 5/6. I could also use
any integer multiple of 6. There is no greatest common
denominator, because I can always choose a larger one.

The LCD is also known as the LCM (least common multiple).

Perhaps you are thinking of the greatest common factor? The
greatest common factor is the largest integer that evenly divides
all of a set of integers.

A.K.A the Greatest Common Divisor, or GCD, which is perhaps where the
confusion arises from? ("denominator" / "divisor").

- Kevin.
 
J

Jeff

Larry Doolittle said:
Without distracting from the conceptual message, let me
modify a detail. On many computers, much interesting
interaction with the hardware happens by reading and writing
special memory locations. C gives a perfectly clean syntax
for that, using volatile <type>* pointers.

So for instance, an operating system that needed to know if some
hypothetical Ethernet chip had received any new packets could

int packet_cnt;
volatile int *packet_cnt_reg = (volatile int *)0xe7000010;
if ((packet_cnt = *packet_cnt_reg) != 0) {
/* receive a packet */
}

No assembly required. ;-)
And indeed, OS writers use this technique whenever possible, for the
obvious readability and portability-across-architectures advantages
over assembly.

I don't agree. Some feature can be only implemented in assembly. How can we
access the system register CR0 by C language ?
 
C

Chris Torek

True -- but such portability can be overestimated. For instance,
the Lance Ethernet chip has two 16-bit registers (the "RAP" and
"RDP", or Register Address Port and Register Data Port) -- so we
(read "I") wrote a driver using the following data structure
(actually this predated C99 uint16_t; I used plain old unsigned
short):

struct lereg1 {
uint16_t ler1_rdp;
uint16_t ler1_rap;
};

Now, you might think a "volatile struct lereg1 *" variable would
suffice to access these on any machine on which the hardware can
be plugged in -- but you would be wrong.

On the MIPS as used in the DECstation, for instance, the data
structure above is wrong. It needs to read:

struct lereg1 {
uint16_t ler1_rdp;
uint16_t ler1_pad1;
uint16_t ler1_rap;
uint16_t ler1_pad2; /* optional */
};

The reason is that the CPU always does 32-bit transactions on the
bus, so in order to make sure that I/O to the RDP does not also
read or write the RAP (and vice versa), the hardware is physically
wired up with Lance address line A1 connected to bus address line
A2.

Now, one might dismiss this as a special case ... but then there
are architectures in which accesses to "memory" that does not
actually work like RAM must be preceded and/or followed by specal
I/O-barrier instructions. These instructions should (perhaps
even "must") *not* be used for accesses to shared-memory variables,
however, which would also be labeled "volatile", hence the compiler
should not automatically insert them. Instead, C code that reads
or writes the RAP and RDP needs explicit barrier instructions as
well.

In short, while abstracting the details is a good idea, it only
takes you partway. Using "volatile" and other such tricks is
necessary, but may not be sufficient. As an OS writer, I just code
what I know is needed now and try to leave enough room for later
"improvements". :)

Jeff <[email protected]> said:
I don't agree. Some feature can be only implemented in assembly. How can we
access the system register CR0 by C language ?

Indeed, some architectures make it impossible to do anything
"not memory-like" using "memory-like" accesses. For instance,
instead of reading the RAP and RDP with "volatile struct lereg1 *"
pointers, we might have to do something like:

io_port_write(LANCE_RAP, 1); /* point to register 1 */
result = io_port_read(LANCE_RDP); /* read register 1 */
/* replaces: reg->ler1_rap = 1; result = reg->ler1_rdp; */

On the Intel x86 in particular, one may need to use the "inw" and
"outw" instructions here.

Some (many?) C compilers offer some sort of "escape to assembler"
feature so that one can write inw() and outw() without having to
use actual subroutine calls (a waste of both code space and CPU
time, on the x86). These features are not only hardware-dependent,
they are compiler-dependent as well. GCC's "__asm__ volatile"
syntax does not work in Microsoft C compilers. (You need the
"volatile" as well as the __asm__ keyword to prevent GCC from moving
and combining the instruction when it has indescribable side
effects.)

What this all boils down to, though, is what I think Lew Pitcher
was getting at here:

which can be rephrased as: "If -- and only if -- the hardware is
*extremely* cooperative (and hardware never is), one could write
an entire OS without ever stepping outside the bounds of C syntax
and with only `slightly dubious' semantics, such as assuming that
particular hardware devices are at particular numeric addresses,
and that casting integer constants to the right pointer types allows
you to access them this way." The source code would not be portable,
and even changing the compiler could cause it to fail (if, e.g.,
the new compiler does not have the same semantics for
integer-to-"pointer-to-hardware-device" conversions).

Since the hardware *never* cooperates to this extent, and since
the constructs needed for working around the balky hardware are
themselves not portable, operating systems are never written in
nothing but Standard C. At best, the majority of the OS code
is Standard C, so that only a small minority of code needs to be
rewritten for each port (to new hardware and/or new compilers).
(Performance factors often get in the way here too -- more code
is machine- and compiler-dependent than strictly necessary, in
these OSes, because the result is a system that runs 30% faster.)
 

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,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top