Has thought been given given to a cleaned up C? Possibly called C+.

  • Thread starter Casey Hawthorne
  • Start date
D

Dag-Erling Smørgrav

Richard Delorme said:
The problem is for the compiler to know the type of a function without
asking the programmer to explicitly write a function declaration. If
the function is defined in the same compilation unit I guess there is
no much problem. When using several compilation units, we need to tell
the compiler on how to find the information by itself. We can imagine
several ways to achieve this:
- In the source file, use a new instruction that indicates where to
find the function type. For example:

#interface "square.c"

int main()
{
/*... code using the function square... */
}

So #interface will open the square.c file and decipher the function
type from its definition.

What if square.c is not available?

DES
 
K

Keith Thompson

Willem said:
Keith Thompson wrote:
) Currently, I can have a file "square.c" that defines a number
) of functions, and another file "square.h" that provides visible
) declarations for *some* of them. Given your #interface proposal,
) how do I specify that some functions in "square.c" are intended to
) be used by client code, and some are internal?

Err... You could use the 'static' keyword ?

Ok. What if I want to define two different interfaces for the same
*.c file. Say one that makes a certain set of functions visible for
general use, and another that makes a larger set of functions visible
for semi-internal use. That's easy to do with header files.
) Is #interface supposed to replace #include? If so, what about
) declarations for things other than functions (constants, typedefs,
) etc.)?

It could pick up all constants, typedefs, variables and macros that
are not declared 'static' ?

"static" doesn't apply to typedefs or macros.

The basic issue here is whether interface and implementation should
be physically separated. Eiffel, IIRC, doesn't do this; a single
source file defines a package/module/whatever, and the compiler
extracts the portions of it that are intended to be visible. (I think
there's a separate tool that produces a human-readable interface
specification.) Ada, on the other hand, forces you to physically
separate the interface from the implementation, and gives you a
compile-time error if they don't match.

There are legitimate arguments in favor of both approaches.
I personally prefer the physical separation. C as it's currently
designed doesn't really enforce either approach, but the traditional
use of .h and .c files encourages separation. Richard Delorme seems
to be advocating the other approach. There's nothing necessarily
wrong with that, but it's a radical change to the language with,
IMHO, not enough benefit to justify it.
 
N

Nick

Willem said:
Keith Thompson wrote:
) Currently, I can have a file "square.c" that defines a number
) of functions, and another file "square.h" that provides visible
) declarations for *some* of them. Given your #interface proposal,
) how do I specify that some functions in "square.c" are intended to
) be used by client code, and some are internal?

Err... You could use the 'static' keyword ?

How about labelling the functions you want exported "extern"al? Just to
give that otherwise pointless marking some purpose. Then ones marked
neither "static" nor "extern" could be - well we'll think of something.
We've overloaded "static" so much, it's time we redressed the balance
slightly.
 
J

Jens Schmidt

Dag-Erling Smørgrav said:
Were there still linkers at that point which did not already meet those
requirements?

Yes. The VMS was ignoring case until then. Around that time it got an
option to preserve case. The maximum significant name length was
unchanged at 31.
 
I

Ian Collins

Le 17/03/2010 18:44, Keith Thompson a écrit :


From the programmer point of view this is a simplification. What I
would appreciate, is to transfer some complexity from the programmer to
the compiler.

By adding a set of unnecessarily complex set of lookup rules?
This is exactly the opposite of what restrict is doing in
current implementations.

How so? There's no way for a compiler to know what is going to be
passed to a function.
 
R

Richard Delorme

Le 17/03/2010 23:03, Keith Thompson a écrit :
Ok. What if I want to define two different interfaces for the same
*.c file. Say one that makes a certain set of functions visible for
general use, and another that makes a larger set of functions visible
for semi-internal use. That's easy to do with header files.

I wonder if this is not a confusion between documentation and header
files. For your example, just provide two documentations, one for
internal usage and another one for general usage.
The basic issue here is whether interface and implementation should
be physically separated. Eiffel, IIRC, doesn't do this; a single
source file defines a package/module/whatever, and the compiler
extracts the portions of it that are intended to be visible. (I think
there's a separate tool that produces a human-readable interface
specification.) Ada, on the other hand, forces you to physically
separate the interface from the implementation, and gives you a
compile-time error if they don't match.

There are legitimate arguments in favor of both approaches.
I personally prefer the physical separation. C as it's currently
designed doesn't really enforce either approach, but the traditional
use of .h and .c files encourages separation. Richard Delorme seems
to be advocating the other approach. There's nothing necessarily
wrong with that, but it's a radical change to the language with,
IMHO, not enough benefit to justify it.

I do not know for the general cases, but in a few projects of mine,
header files (excluding standard ones) contain between 5% to 10% of
lines of codes. So removing them is a productivity enhancement of about
5 to 10%. I think it's not a negligible benefit.
 
R

Richard Delorme

Le 17/03/2010 23:09, Ian Collins a écrit :
By adding a set of unnecessarily complex set of lookup rules?

The programmer won't care much of this set of lookup rules.
How so? There's no way for a compiler to know what is going to be passed
to a function.

Yes there is, using alias analysis.
 
R

Richard Delorme

Le 17/03/2010 23:02, Dag-Erling Smørgrav a écrit :
What if square.c is not available?

#interface "square"

The instruction meaning the compiler is going to look for the interface
in the file libsquare.a or square.dll or whatever depending on the
implementation.
 
A

Alan Curry

| - In the source file, use a new instruction that indicates where to
|find the function type. For example:
|
|#interface "square.c"
|
|int main()
|{
| /*... code using the function square... */
|}
|
|So #interface will open the square.c file and decipher the function type
|from its definition.

So I have to keep a permanent local copy of the full source code of every
library I want to compile against? Currently I only need the header files and
compiled lib*.(a|so) and as someone who doesn't buy a new hard drive every 6
months, I like it that way.

There are even some libraries that are deliberately distributed without
source code, so the users only have the header files and object code to work
with. Those people won't like your idea either.
 
S

Seebs

Le 17/03/2010 23:09, Ian Collins a écrit :
The programmer won't care much of this set of lookup rules.

I'm not at all convinced. This sounds like a nightmare to me -- I'd
never know where things were coming from or which things were liable to
come from somewhere.

That said!

I would be 100% in favor of a change to require 2-pass compilation, that
is to say, requiring only that a function be declared or defined SOMEWHERE
in a translation unit, rather than "before it is used". I think that would
make C a lot more consistent, and I really don't feel that the cost to
compiler vendors is all that bad.

-s
 
K

Keith Thompson

Richard Delorme said:
Le 17/03/2010 23:03, Keith Thompson a écrit :

I wonder if this is not a confusion between documentation and header
files. For your example, just provide two documentations, one for
internal usage and another one for general usage.

I don't think so. If I try to call an internal function, I want the
compilation to fail.

[...]
I do not know for the general cases, but in a few projects of mine,
header files (excluding standard ones) contain between 5% to 10% of
lines of codes. So removing them is a productivity enhancement of
about 5 to 10%. I think it's not a negligible benefit.

That assumes that productivity depends merely on the number of
lines of code. I don't think that's a valid assumption.

I suppose you could write a tool that automatically generates a
..h file from a given .c file. You could then edit it to remove
anything you don't want visible to clients. (Maybe IDEs already
do this kind of thing?)

Incidentally, I don't see much point in cross-posting to
comp.lang.c.moderated and comp.lang.c. I'm cross-posting this
response, but directing followups just to clcm.
 
I

Ian Collins

Le 17/03/2010 23:09, Ian Collins a écrit :

The programmer won't care much of this set of lookup rules.

He/she would if they enforce code layout rules, imaging several source
files this the same named function in them, or a library without source.
Yes there is, using alias analysis.

So the writer/compiler of memcpy() knows all possible uses of the
function? Interesting, psychic compilers!
 
N

Nick Keighley

binary and text mode work fine if you apply them appropriately

you've got a problem whatever mode you use if you port text files
between platforms.
Even considering only systems using CR, CR/LF, or LF, C's text mode can go
wrong: reading in a file created on a computer with a different newline
sequence, or writing a text file on this computer and reading it on one
using a different sequence.

so you convert it... Binary mode doesn't solve the problem.
And then there are hybrid files which are mainly binary data, but also
contain embedded text that can include newline characters.

not a text file. You'll have to have some way of detecting the text
bits and then writing your own parser.
Which means that
binary data that looks like CR/LF gets converted to LF (and the entire file
shrinks in size by one byte), or vice versa.
and?

I suspect people who advocate text mode tend to use machines with a single
character newline, and simply don't see the problems it creates when newline
is multiple characters.

I'd have thought the opposite. Its the unix people who don't really
understand text mode (becasue they don't need it). Its the DOS people
who understand text mode (because the do need it). You are aware that
C's i/o library hides the double character EOL sequence from the
application?
 
B

bartc

Nick said:
binary and text mode work fine

I know binary does.
if you apply them appropriately

Oh I see: if you work around the problems...
so you convert it... Binary mode doesn't solve the problem.

I haven't figured out how to do that, without a detailed knowledge of either
source or destination format.

And if I knew how (and when), I wouldn't need to convert...
I'd have thought the opposite. Its the unix people who don't really
understand text mode (becasue they don't need it).

I was suggesting the advocates were mainly using the newline=LF systems, in
other words, text mode = binary mode. Ie. in line with your comment.
You are aware that C's i/o library hides the double character EOL sequence
from the
application?

I was aware it doesn't do a good job. Although if files are only ever
processed serially, a character at a time, then it's workable.

I had a problem once where I was outputting a string containing embedded
CRLF sequences via printf(). The output became CRLFLF (on my machine). When
redirected to a file, it caused some programs to go wrong.

(Why was CRLF embedded? I was calling C's printf() from a language which
chose not to abstract away the machine's newline sequence. Now maybe C's
printf() should only be called from actual C source code, but C is popular
for helping build other languages on top of it. Why should these languages
then have C's quirks with newline imposed on them too?

To solve this, I had to call some function or other which set stdout to
binary mode.)
 
B

bartc

That's why I asked Richard D to explain just what *he's* proposing.

I think *I* may have been confused by the fact that forward declarations,
and external declarations, look exactly identical in C.

I touched on this in "Name Spaces" in my post on eyebrow-raisers elsewhere
this thread.

Apparently this is how declarations at filescope (ie. outside functions)
work in C:

int fn(int);

EITHER: If fn() is defined later on: this is a Global function
which is exported from this module, and visible to all others.

OR: if fn() is not defined here, this is a Global function which
is imported from another module.

int abc;

Global variable, ie. shared across all modules.If this happens to
be already in use, at filescope in another module about which
you might know nothing about, then it will clash!

And if the variable is initialised, you can't initialise it in a shared
header, because then each module will attempt to initialise it's
copy.

static int fn(int);

Local function declared later in this module

static int abc;

Variable directly visible only in this module.

typedefs, structs, enums, #defines

Are always local to this module. To share across modules, duplicate
in those other modules. Then the other modules will think they are
local to *them*. Since no runtime resources are involved, this doesn't
matter.

To summarise, I would say that to an outsider, it looks a bit of a mess.
 
B

Ben Bacarisse

bartc said:
I had a problem once where I was outputting a string containing embedded
CRLF sequences via printf(). The output became CRLFLF (on my machine). When
redirected to a file, it caused some programs to go wrong.

Either there was a bug in the C library (so I don't think you should
blame C) or you asked it to do this by using text mode on a stream
where you wanted the output to be literal.
(Why was CRLF embedded? I was calling C's printf() from a language which
chose not to abstract away the machine's newline sequence. Now maybe C's
printf() should only be called from actual C source code, but C is popular
for helping build other languages on top of it. Why should these languages
then have C's quirks with newline imposed on them too?

They don't have to. It sounds as if you were using text mode when the
data was not text (in the C sense of the word). Languages that use
C's IO library get to choose between using C's admitted less that perfect
solution to the problem or tackling it themselves (or ignoring it, of
course, if that suits the situation).
To solve this, I had to call some function or other which set stdout to
binary mode.)

So where is the problem? It looks like this is what you wanted right
form the start.

You rail against C's attempt to help with a messy problem, but what
would you rather have? You could roll back the clock to K&R C which
did not have this distinction between streams, but it soon became
apparent the something needed to be done. Without some attempt to
tackle the issue, even K&R's "hello world" program would not run
correctly on machines that did not use \n as the line termination.
 
B

bartc

Ben said:
They don't have to. It sounds as if you were using text mode when the
data was not text (in the C sense of the word).

It was quite a literal string. And someone might anyway want to output
binary codes using printf(), why not? Perhaps there is a problem with using
an actual file. Perhaps the stdout output is to be piped to another program
which does some more processing. There's any number of reasons why a binary
stdout is useful.
So where is the problem? It looks like this is what you wanted right
form the start.

Yes, I had to use this code:

void setbinaryconsole(void) {
_setmode(_fileno(stdout),_O_BINARY);
}
You rail against C's attempt to help with a messy problem, but what
would you rather have?

Only that text mode had a lower profile. It seems to be the default mode on
fopen(), and the default mode (with obscure, awkward, and
not-easily-portable overrides) on stdout.

If text mode was also to convert tabs to spaces and vice versa, you'd know
how I feel about it messing with newlines.
 
N

Nick Keighley

Okay, I am convinced.  There does still exist a use for strncpy.  And a
pretty well considered one.

What it isn't, though, is a "safe replacement for strcpy".  :)  By contrast,
strlcpy sort of is.  (Not totally, but enough better that I'd use it by
preference if it were in the spec.)

I'd be happier with strncpy() if it had a different name (fstrncpy?).
Too many people see it begins with str and assume it "works like
strcpy()". It would help if people rea rthe documentation, of course
 
N

Nick Keighley

Le 16/03/2010 16:47, Nick Keighley a écrit :


Well it already works in other languages like java, caml, etc. And it
almost already works in C:

I must have seen too much Pascal at an impressionable age
 
J

Jasen Betts

Okay, I am convinced. There does still exist a use for strncpy. And a
pretty well considered one.

What it isn't, though, is a "safe replacement for strcpy". :) By contrast,
strlcpy sort of is. (Not totally, but enough better that I'd use it by
preference if it were in the spec.)

if you have't got strlcpy you can use sprintf with a length...

#define alt_strncpy(d,s,l) if(l)sprintf(d,"%.*s",l-1,s)


--- news://freenews.netfront.net/ - complaints: (e-mail address removed) ---
 

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
474,102
Messages
2,570,645
Members
47,246
Latest member
TemekaLutz

Latest Threads

Top