John McCarthy died today.

N

Nick Keighley

I'm working on a program that can be built either with a C or C++ compiler.
Most of the time I forget about this, losing my awareness of "this has tobe
valid C++ too", and I neglect to build it as C++ for weeks or months.

Yet, the C++ port very rarely breaks and is easy to fix.

I just tried a C++ build: zero warnings! According to the ChangeLog, the last
time I did C++-related maintenance was on Oct 2, which was 131 commits ago. So
did 131 commits to a C program without caring that it's also C++, yet it still
compiles cleanly as C++.

C++ is a very close dialect of C, and can easily be treated as another porting
target for a C program.

"the C subset of C++ is a very close dialect of C..."
 
I

Ike Naar

One example would be that I can't build the code any more with C++ to check
that all external names are meeting type-safe linkage and the one-definition
rule.

In C, I can have "extern int x;" in in one module, and "struct foo x = { 0 };"
in another. It will link.

If you change a C program such that a function has different parameters, but
due to some broken dependencies in your build system, some dependent modules
are not recompiled, you will get a broken link. Of course, it goes away
if you do a complete rebuild, but you could waste time chasing a bug
which isn't there.

This is fixed in C++: it will catch your broken build system. Type
safe linkage won't let an int (int, char *) call go to an
int (int, char *, char *) function.

Using a C++ compiler (GCC 4.1.2), the following:

/* a.cxx */
extern int x;
int main() { return x; }

/* b.cxx */
struct foo { double d; } x;

compiles/links (c++ -ansi -pedantic -Wall a.cxx b.cxx)
and runs without any complaints.
 
K

Kaz Kylheku

Using a C++ compiler (GCC 4.1.2), the following:

/* a.cxx */
extern int x;
int main() { return x; }

/* b.cxx */
struct foo { double d; } x;

compiles/links (c++ -ansi -pedantic -Wall a.cxx b.cxx)
and runs without any complaints.

Ah yes, g++ is broken in this regard.

But the ODR still kicks in.

In a program where there are duplicate uses of an external name like this,
there are likely to be multiple definitions. E.g. two modules in some large
program both happen to use a global variable x.

Perhaps two developers did parallel commits in different modules, both
introducing it, and you, the build master, pull both changes from the repo.

$ cat a.cc
int x;
$ cat b.cc
struct foo { int a; } x;

int main()
{
}
$ g++ a.cc b.cc
/tmp/ccJExOCi.o:(.bss+0x0): multiple definition of `x'
/tmp/ccbKi3U5.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status

So at least there is that. Of course if one module, by mistake, neglects to
define its global, then the ball gets by the goalkeeper, so to peak.

If these changes are made separately (e.g. two developers in separate
sandboxes) the one with the missing definition will hopefully catch it, since
it doesn't link.

But change to C:

$ cp a.cc a.c
$ cp b.cc b.c
$ gcc a.c b.c

Multiple defs; not a peep.

If "perfect" is not available, I will still take "better".
 
J

James Kuyper

Ah yes, g++ is broken in this regard.

But the ODR still kicks in.

There's only one definition of 'foo' in this program; the one in b.cxx.
a.cxx only contains a declaration of the object. Even if this were a
violation of the ODR, section 3.2p3 of the C++ standard says, very
explicitly, "no diagnostic required", which would make it no different
from C in this regard.

The relevant rule is actually in section 3.5p10 of the C++ standard:
"... the types specified by all declarations referring to a given object
or function shall be identical, ...", but in that case, too, it says
very explicitly that "A violation of this rule on type identity does not
require a diagnostic." So again, it's no different from C.

If some C++ compilers provide diagnostics that are not required, that's
a feature of those particular compilers, not a feature of the C++
language itself, and a feature that could have been put into C compilers.

(all citations are from n3035.pdf, which is the closest thing I have to
the actual C++ standard that is readily available. However, I don't
believe that either of these citations are significantly different from
previous versions of the standard, nor from more recent drafts of the
next standard).
 
B

Ben Bacarisse

Kaz Kylheku said:
On 2011-11-14, Ike Naar <[email protected]> wrote:

Ah yes, g++ is broken in this regard.

But the ODR still kicks in.

In a program where there are duplicate uses of an external name like this,
there are likely to be multiple definitions. E.g. two modules in some large
program both happen to use a global variable x.
But change to C:

$ cp a.cc a.c
$ cp b.cc b.c
$ gcc a.c b.c

Multiple defs; not a peep.

If "perfect" is not available, I will still take "better".

-fno-common is handy for this.
 
D

David Thompson

Those languages were likely implemented in C. In which case, they would be
quite receptive to the idea of using "=" and "==".
The implementation language as such doesn't matter; SQL and HTML,
among many other things, are often implemented in C (or C++, which
keeps all the same basic syntax) but look nothing alike.
And if they had considered using ":=" and "=" instead, they would quickly
have found that mixing up ":="/"=" and "="/"==" (between writing the C code
and testing fragments of the new language) caused too many problems!
That's a benefit, but I think a small one. More important, if the
designers/ implementors have experience of using C (or C++) without
trouble, and especially if they expect or find their users do so, then
following the path already blazed makes life easier.
In the original C, or the derived languages? Once the decision to use "="
for assignment in C was made, using "==" for equality was reasonable. Using
.EQ. would be too naff, and using context was not possible as assignments
also occur in expressions.

(I think PL/I allowed "=" for both assignment/equality, maybe it did use
context, but that was quite hairy to implement anyway.)

PL/I does indeed, but it has assignment as a statement only at
toplevel not a nestable expression. The harder problem in parsing
PL/I, for both compiler and human, is unreserved keywords.

COBOL similarly has no trouble distinguishing
COMPUTE x = y .
IF a = b THEN blah .

and SQL
SELECT x FROM t WHERE y = 3;
UPDATE t SET x = 17;
 

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top