I Keep Switching Back...

K

Kamilche

I'm looking at other languages. Some of them fool me into thinking
they're useful, and I change my home page to them... 'comp.lang.c++'
for instance. But I always end up switching it back to comp.lang.c.
:-D

When I redid my code into C++ recently, I saw some amazing bogosities.
Such as member functions being called before the constructors ran, and
member functions being called for NULL objects. Enough to make me
switch back to C, where function calling order is controlled by the
programmer, and proceeds in a safe and sane order. :-O

So - I'm baaaack. :-D I haven't encountered a good enough language yet
that has made me switch my home page permanently.

--Kamilche
 
B

Ben Pfaff

When I redid my code into C++ recently, I saw some amazing bogosities.
Such as member functions being called before the constructors ran, and
member functions being called for NULL objects. Enough to make me
switch back to C, where function calling order is controlled by the
programmer, and proceeds in a safe and sane order. :-O

C++ has a really, really scary amount of complexity. Personally,
a few months ago I embarked on trying to learn it well enough to
use it for real projects, by way of buying all the best books on
it and summarizing their advice, with citations, into a "best
practices guide" for myself. So far, I have over 10,000 words
citing 18 books and articles, and I still have quite a way to go.
 
J

Joe Wright

Kamilche said:
I'm looking at other languages. Some of them fool me into thinking
they're useful, and I change my home page to them... 'comp.lang.c++'
for instance. But I always end up switching it back to comp.lang.c.
:-D

When I redid my code into C++ recently, I saw some amazing bogosities.
Such as member functions being called before the constructors ran, and
member functions being called for NULL objects. Enough to make me
switch back to C, where function calling order is controlled by the
programmer, and proceeds in a safe and sane order. :-O

So - I'm baaaack. :-D I haven't encountered a good enough language yet
that has made me switch my home page permanently.
Welcome back. We've missed you.
 
K

Kamilche

Richard Heathfield said:
Welcome back to the comp.lang.c newsgroup.

We've moved the coffee machine to make room for another server. You'll now
find it in the cafeteria, next to the swing doors.

Your cloakroom peg has been re-assigned, so please apply for a new one when
you pick up your swipe card.

Don't forget to unsubscribe from comp.lang.c++ :)

:-D
Kamilche plops a plate of cookies next to the water cooler, and
surveys her old digs happily.
 
K

Kamilche

Ben Pfaff said:
(e-mail address removed) (Kamilche) writes:

C++ has a really, really scary amount of complexity. Personally,
a few months ago I embarked on trying to learn it well enough to
use it for real projects, by way of buying all the best books on
it and summarizing their advice, with citations, into a "best
practices guide" for myself. So far, I have over 10,000 words
citing 18 books and articles, and I still have quite a way to go.

Yeah, I believe it. But when push comes to shove, what I saw looked
and smelt more like bugs than complexity. I saw member functions being
called before the constructor was called, and learned you can't rely
on constructor initialization order for global objects. So I turned
them into pointers instead, and discovered that C++ will call member
functions for objects that DON'T EVEN EXIST. They can be NULL, and you
can still call their functions. The function gets a NULL 'this'
pointer!

The following code compiles and runs, and A() executes. Apparently the
object orientation of C++ is a thin scum over procedural programming,
UNRELIABLE procedural programming at that, to allow code like this to
execute. That's when I put it down and walked away from it.

class My
{
public:
void A()
{
if (this==NULL) printf("NULL Pointer ");
}
};

void main()
{
My *ptr=NULL;
ptr->A();
}

I feel that by going to C++, I'd be giving up the complexities
inherent in large C programs, for the undiscovered bugs in C++... ya
know? I know object oriented programming from other languages, such as
VB... and this is just not the way it should work.

I've been doing a huge amount of experimenting with hierarchical
objected oriented C systems. Right now, I'm looking at code
generation, or possibly heavy use of configuration files, to reduce
complexity... something where I can keep the high level 'big picture'
pseudocode in a text file, and either load it at startup, or auto
generate code from it.
 
C

Chris Torek

Yeah, I believe it. But when push comes to shove, what I saw looked
and smelt more like bugs than complexity. I saw member functions being
called before the constructor was called, and learned you can't rely
on constructor initialization order for global objects.

(This is probably the wrong newsgroup to gripe about such things,
but as far as I am concerned, this ordering problem is just the
tip of the iceberg.)
So I turned them into pointers instead, and discovered that C++ will
call member functions for objects that DON'T EVEN EXIST. They can be
NULL, and you can still call their functions. The function gets a NULL
'this' pointer!
Yes.

The following code compiles and runs, and A() executes. Apparently the
object orientation of C++ is a thin scum over procedural programming ...

Actually, it is a fairly thick layer. But for simple cases like
this one, there is a direct conversion from C++ to C:
class My
{
public:
void A()
{
if (this==NULL) printf("NULL Pointer ");
}
};

(You need to #include at least one header, and the printf here
should really be "std::cout <<", etc. But never mind that.) Here
the "class function" A() that is a member of the data structure
called "My" is obtained simply by gluing together the type ("My")
and the function name ("A"), which you can do manually in C by
spelling it My_A(). Of course, you give up the automatic "if the
type changes, the function name changes too" part that C++ gives
you.
void main()
{
My *ptr=NULL;
ptr->A();
}

This needs to be "int main()" just as in C.

In any case, the C++ compiler here just glues together (in a
more error-resistant way) the name "My" and the name "A", so
this is like writing the C code:

struct My { char dummy; };
/* dummy element required only because C forbids empty struct */

void My_A(struct My *this) {
if (this == NULL)
printf("NULL pointer\n");
}
int main(void) {
struct My *ptr = NULL;
My_A(ptr);
}

If you change member function A to "virtual", it stops working.
This is because a "virtual" member function is not built by name
-- i.e., we no longer just say "well gosh, `ptr' has type `My' so
we just call My_A() and supply `ptr' as a secret argument for the
`this' parameter". Instead, there is now a "virtual function table"
attached to the data type.

This is where C++ actually gives up something you can do manually
in C. For various (good and bad) reasons, the virtual function
table is essentially an operations vector, and the data structures
-- objects of type "My" -- point to the table. So in C we might
now write:

struct ops_for_My {
void (*A)(struct My *this);
};
static struct ops_for_My ops_for_My = { A };
struct My {
struct ops_for_My *vtable;
/* other data elements go here as needed */
};

When you create an actual object of type "My", the compiler will
fill in the "vtable pointer":

/* C code loose-equivalent of the C++ stuff */
ptr = ...;
ptr->vtable = &ops_for_My;

A later call of the form:

ptr->A(); // in C++

translates to the C call:

ptr->vtable->A(ptr);

and if "ptr->vtable" points to the default table, that calls the
default "My_A()" function. (A derived class that overrides the
default My_A() function just requires another ops table, with a
different "A" pointer.)

Although the need is somewhat specialized and occasional, note that
if you have written this in C, you now have a name for the vtable(s)
that implement the "virtual functions" for anything that is, or is
derived from, a "My". Clearly, if ptr==NULL, this:

ptr->vtable->A(ptr);

is not going to work -- but in C, we can do this instead, in
those rare cases where we want to:

ops_for_My.A(NULL);

In C++ one has to resort to any number of workarounds -- not that
they are particularly horrible or anything; but it is annoying to
know that there is a virtual function table all set up, yet you
are not allowed to access it. You *must* have an instance of the
class in order to access that class's virtual function table.
(The easiest workaround is thus to have a static "dummy" instance.)

In any case, both regular "class functions" and "virtual functions"
are easy to do in C, using these techniques. C++ merely automates
some of the drudge-work, avoiding the opportunity to get it wrong,
but also requiring you to give up some control over it.
 
N

Niklas Norrthon

I'm looking at other languages. Some of them fool me into thinking
they're useful, and I change my home page to them... 'comp.lang.c++'

Currently I mostly use C for my work, but I have some 10 years of C++
experience too. I also like other languages like to study scheme,
haskell et cetera, and my conclusion is that there is no "one
language" that is good for everything. C is a great language,
and so is C++.
When I redid my code into C++ recently, I saw some amazing bogosities.
Such as member functions being called before the constructors ran,

What did you do?

Perhaps something like the following?
Foo* x;
x->member_func();
and
member functions being called for NULL objects.

The caller is responsible for initializing the objects, calling member
functions for NULL objects is just as much undefined behavior as
the "C" constructs:

int i;
i = i++ + ++i;

and

int* i;
*i = 42;
Enough to make me
switch back to C, where function calling order is controlled by the
programmer, and proceeds in a safe and sane order. :-O

You switch to C because you can't handle the responsibility to initialize
the objects before you use them? Perhaps pascal is a better language
for you...
The following code compiles and runs, and A() executes.

It doesn't for me. I get the following compile errors:

~% g++ -pedantic -ansi -Wall asdf.cc
asdf.cc: In method `void My::A()':
asdf.cc:6: `NULL' undeclared (first use this function)
asdf.cc:6: (Each undeclared identifier is reported only once
asdf.cc:6: for each function it appears in.)
asdf.cc:6: `printf' undeclared (first use this function)
asdf.cc: At top level:
asdf.cc:11: warning: return type for `main' changed to `int'

change printf to std::printf said:
Apparently the
object orientation of C++ is a thin scum over procedural programming,
UNRELIABLE procedural programming at that, to allow code like this to
execute. That's when I put it down and walked away from it.

class My
{
public:
void A()
{
if (this==NULL) printf("NULL Pointer ");
// This can never be NULL, this test is not necessary.
}
};

void main()
{
My *ptr=NULL;
ptr->A();
}

Dereferencing a NULL pointer. I don't understand why you are upset.
This is just as undefined behavior in C++ as the following C program
would be:

#include <stdio.h>

typedef void (*Func)(void);

struct Foo {
Func A;
};

int main ()
{
Foo* ptr = NULL;
ptr->Func();
return 0;
}

Anything can happen in the C-program above, including the output
of some text regarding null-pointers.

I can understand arguments about C++ being a complex language
with lots of things happening "under the hood", but supporting such
arguments with code that invokes undefined behavior, and would
do so even in C, if the constructs had been legal in C is silly.

/Niklas Norrthon
 
B

Bruce Wheeler

On 10 Jul 2003 00:26:13 -0700, (e-mail address removed) (Kamilche) wrote:
....
The following code compiles and runs, and A() executes. Apparently the
object orientation of C++ is a thin scum over procedural programming,
UNRELIABLE procedural programming at that, to allow code like this to
execute. That's when I put it down and walked away from it.

class My
{
public:
void A()
{
if (this==NULL) printf("NULL Pointer ");
}
};

void main()

C++ requires int main, just as C does.
{
My *ptr=NULL;
ptr->A();
}

This is undefined behavior in C++. You are dereferencing a NULL pointer,
which is undefined in C++, just as it is in C. As a clc reader, you know
that anything can happen when undefined behavior is invoked, as in the
following analagous C fragment, also dereferencing a NULL pointer.

char* x = NULL,
strcpy(x, "Hello");

Both code fragments could run "normally", format your hard disk, or
cause a power outage in Birmingham, Alabama.

C++ has problems with undefined behavior similar to C. As Ben Pfaff
commented, C++ is also vastly more complicated than C, but if one writes
good, legal code (avoiding undefined behavior, among other things), C++
is a very useful language.

I would suggest that you learn to write legal C++ before you condemn it.

Regards,
Bruce Wheeler
 
B

Bruce Wheeler

On 10 Jul 2003 01:30:46 -0700, (e-mail address removed) (Niklas Norrthon)
wrote:

A very nice post.

I posted something similar in a different subthread.

However,
// This can never be NULL, this test is not necessary.

Actually, 'this' can be NULL, as the method invocation is undefined
behavior if 'this' is NULL. Anything can happen. Some C++
implementations (VC++ in particular) actually have such code in tests in
library code.
Dereferencing a NULL pointer. I don't understand why you are upset.
This is just as undefined behavior in C++ as the following C program
would be:

#include <stdio.h>

typedef void (*Func)(void);

struct Foo {
Func A;
};

int main ()
{
Foo* ptr = NULL;
ptr->Func();
return 0;
}

Anything can happen in the C-program above, including the output
of some text regarding null-pointers.

Correspondingly, anything (including invocation of the method) can
happen in the C++ example above, because it is also undefined behavior.
I can understand arguments about C++ being a complex language
with lots of things happening "under the hood", but supporting such
arguments with code that invokes undefined behavior, and would
do so even in C, if the constructs had been legal in C is silly.

/Niklas Norrthon

Regards,
Bruce Wheeler
 
Z

Zoran Cutura

Kamilche said:
Yeah, I believe it. But when push comes to shove, what I saw looked
and smelt more like bugs than complexity. I saw member functions being
called before the constructor was called, and learned you can't rely
on constructor initialization order for global objects. So I turned
them into pointers instead, and discovered that C++ will call member
functions for objects that DON'T EVEN EXIST. They can be NULL, and you
can still call their functions. The function gets a NULL 'this'
pointer!

You somehow drew the conclusion that C++ doesn't allow for programmers
to write buggy software, where would this come from? In C++ as in C
you're responsible for writing legal code, not the language.
The following code compiles and runs, and A() executes. Apparently the
object orientation of C++ is a thin scum over procedural programming,
UNRELIABLE procedural programming at that, to allow code like this to
execute. That's when I put it down and walked away from it.

class My
{
public:
void A()
{
if (this==NULL) printf("NULL Pointer ");
}
};

void main()
{
My *ptr=NULL;
ptr->A();
}

I feel that by going to C++, I'd be giving up the complexities
inherent in large C programs, for the undiscovered bugs in C++... ya
know? I know object oriented programming from other languages, such as
VB... and this is just not the way it should work.

I ask myself, why you want to give up C at all. If C is inappropriate
for a problem, use something different, but if it does the job (or if
you think you can do the job in C) why not just stick with it?

A mechanic wouldn't use a hammer when a screwdriver is needed, allthough
I bet that he/she could solve the job with a hammer too.
 
G

goose

<snipped>

class My
{
public:
void A()
{
if (this==NULL) printf("NULL Pointer ");
}
};

void main()

int main (void)
{
My *ptr=NULL;
ptr->A();

dereferencing a null pointer, undefined behavior.
the same effect as doing in C the following:
char *s=NULL;

*s++;

<snipped>

goose,
hand, etc :)
 
K

Kamilche

I would suggest that you learn to write legal C++ before you condemn it.

Hey, that's not even my code! :-D I cut n pasted it from one of the
hundreds of thousands of Google hits discussing this particular
problem with C++. Not to worry, you guys all browbeat into me the
correct usage of int main and common C idioms.

It IS kinda funny tho - 'int main' browbeating isn't as common in the
C++ world as it is in the C world. They've got bigger complaints to
fry. :-O

--Kamilche
 
K

Kamilche

Chris Torek said:
...
In any case, both regular "class functions" and "virtual functions"
are easy to do in C, using these techniques. C++ merely automates
some of the drudge-work, avoiding the opportunity to get it wrong,
but also requiring you to give up some control over it.

Wow, what useful information! Thanks. :) I'm going to sit and
cogitate on it and see how it can be worked into my app.

Maybe it's time to pull out that 'Object Orientation in C' link I
saved, the one that used vtables but seemed too complex to use. I know
C a lot better now... and I know the beast that awaits in C++. :-|

--Kamilche
 
A

Arthur J. O'Dwyer

(e-mail address removed) (goose) wrote...

In C, the above code crashes the app, as is proper.

You've never written C on a DOS box, have you?
In C++, the example I posted merrily runs along,
pretending everything is OK.

You've never written C++ on a Unix box, have you?
An advanced C++ programmer told me that C++ was designed
this way to keep the speed up. I don't think design decisions
qualify as undefined behavior. :-|

What? Are you saying that since you intentionally dereferenced NULL,
that *shouldn't* be undefined? [That's silly.] Or are you saying
that your compiler vendor should have added code to the compiler in
order to make a null-pointer dereference more obvious to the user?
[That's not silly, it's moot.] What "design decisions" are you
talking about?
In my opinion, the app
should have crashed instead of happily calling functions with
a NULL pointer.

Why? Isn't a program crash just as bad? Don't both things qualify
as undefined behavior (yes)? Wouldn't both things merit a bug report
and/or loss of your client's business in the Real World (yes)?

Why would you try to compile that program anyway, *knowing* that it
was not correct? (If your answer is: To gain experience - well,
consider yourself gained.)

-Arthur
 
B

Ben Pfaff

[responding to me]
For some people, it's hard to accept that they have come to the end
of their productive lives and step aside for the new generation.

Sad that I've come to "the end of my productive life", then, at
the ripe old age of 24.
 
D

Default User

Kamilche said:
But I do have a bit more to add, for those that claim it's my sucky
C++ skills. You know what? I AM fallible and imperfect! I DON'T get
things right the first time! My apps crash, and I have to use the
development environment to track things down! Once I discover what is
wrong, I fix it, run it again, and gain a little bit of wisdom. I
freely admit this.

What books were you using to learn C++?
But what if you get it wrong, and the program KEEPS RUNNING, as in the
example I posted? That's quite a bit larger mess than I had in C.

You seem to be laboring under the misapprehension that C cannot just got
blithely on about its business when you have a gross error in your code.
You ought to know better than that.
Anyways. I see where you're all coming from, calling it 'undefined
behavior.' I'm sure if I understood C++ perfectly, and never made a
coding error, I'd avoid these 'undefined behavior' areas, and have no
problems with C++. But since I AM fallible, I need it to jump up and
bite me in the butt... the first time it runs. I suppose you could
argue that the problem boils down to, C++ doesn't exhibit enough
'DeathStation 9000' behavior for my taste.

Again, EXACTLY the same thing can happen with C. Notably, writing off
the end of an array. That may crash. It may not. It may "work" for two
years, then crash.

Learn the language properly.



Brian Rodenborn
 
K

Kelsey Bjarnason

[snips]

In C, the above code crashes the app, as is proper.

Really? Where does the standard guarantee a crash? Whoops, it doesn't;
the behaviour is undefined. It could crash, it could run, it could set
your hamster on fire. Expecting any particular behaviour is an error on
your part, not the language's.
 
K

Kamilche

Default User said:
Learn the language properly.

Well, I'll admit, the book I was using, 'Teach yourself C++ in 21
days', left much to be desired. They didn't cover many basic things,
not even the use of the string library.

The undefined constructor initialization order was not mentioned, nor
was the 'you can pass anything in as a pointer and it will
brain-deadedly treat it as an instance of that type, and execute the
member function for it.' If it had, I may have stopped before I'd
wasted too much time. :-D

--Kamilche
 
B

Ben Pfaff

Programmer Dude said:
Meanwhile, at 48, I've been using C++ quite happily for a couple
years now. I love it! ;-)

It seems that some people are having trouble spotting my sarcasm
directed at ERT.
 
A

Arthur J. O'Dwyer

It seems that some people are having trouble spotting my sarcasm
directed at ERT.

Hmm. And here I thought Chris was commiserating with you - he's
obviously reached the end of his productive life, if he uses C++
and *likes* it!

;-)
-Arthur
 

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

Latest Threads

Top