Newbie questions (four of them)

E

E. Robert Tisdale

CBFalconer said:
Pointers to functions can implement "methods"
and be stored within a struct.
The usage is just somewhat different.
What he may miss most is overloading.

Let me try:
typedef int (*addp)(int, int);
typedef struct foo { // base class
int a, b;
addp* pvtable;
} foo;
int addlogic(int a, int b) {return a ^ b;}
const addp foo_vtable[] = { addlogic };
foo foo_create(int av, int bv) {
foo f;
f.a = av;
f.b = bv;
pvtable = foo_vtable;
return f;
}

int foo_add(const foo* p) {
return (p->pvtable[0])(p->a, p->b);
}
typedef struct bar { // derived class
foo f;
} bar;
int addarith(int a, int b) {return a + b;}
const addp bar_vtable[] = { addarith };
bar bar_create(int av, int bv) {
bar b;
b.f.a = av;
b.f.b = bv;
b.f.pvtable = bar_vtable;
return b;
}

int bar_add(const bar* p) {
return (p->f.pvtable[0])(p->f.a, p->f.b);
}

int main(int argc, char* argv[]) {
const bar b = bar_create(13, 7);
return foo_add((const foo*)(&b)); // 13 + 7 = 20
}
 
C

CBFalconer

Sidney said:
CBFalconer said:
[...] C can largely implement Java, but not the converse.

To me, that's a rather aenigmatic statement.

If there is to be any comparison between the inherent expressive power
between standard Java and standard C, I'd personally select Java as the
more powerful one, if only because it has a standard library that covers
many areas of application (GUI, networking, ...) where the C standard
is silent.

Now don't get me wrong: I don't like Java all that much for a variety of
reasons, but still your statement is puzzling. Would you care to elaborate?

Leave out the libraries and start with raw metal. C is almost
capable of building anything an assembler can. Java (and most
languages) is not. This is more or less the condition many
embedded systems must cope with.
 
D

Dik T. Winter

> CBFalconer wrote:
>
> > [...] C can largely implement Java, but not the converse.
>
> To me, that's a rather aenigmatic statement.

To me not. I would say that it means that in C you can implement
a Java compiler or interpreter or whatever, but not the converse.
Whether that is true? I do not know. C is a universal TM. Is
Java? If you have a universal TM you can implement actually
anything. It appears that even Vi is a universal TM. At least
you can solve mazes in it.
 
C

CBFalconer

*** WARN WARN WARN Trollsdale strikes again - see end ***

E. Robert Tisdale said:
CBFalconer said:
Pointers to functions can implement "methods"
and be stored within a struct.
The usage is just somewhat different.
What he may miss most is overloading.

Let me try:
typedef int (*addp)(int, int);
typedef struct foo { // base class
int a, b;
addp* pvtable;
} foo;
int addlogic(int a, int b) {return a ^ b;}
const addp foo_vtable[] = { addlogic };
foo foo_create(int av, int bv) {
foo f;
f.a = av;
f.b = bv;
pvtable = foo_vtable;
return f;
}

int foo_add(const foo* p) {
return (p->pvtable[0])(p->a, p->b);
}
typedef struct bar { // derived class
foo f;
} bar;
int addarith(int a, int b) {return a + b;}
const addp bar_vtable[] = { addarith };
bar bar_create(int av, int bv) {
bar b;
b.f.a = av;
b.f.b = bv;
b.f.pvtable = bar_vtable;
return b;
}

int bar_add(const bar* p) {
return (p->f.pvtable[0])(p->f.a, p->f.b);
}

int main(int argc, char* argv[]) {
const bar b = bar_create(13, 7);
return foo_add((const foo*)(&b)); // 13 + 7 = 20
}

I have left the whole gory mess because Trollsdale has again
edited the quoted material. I DID NOT WRITE what Trollsdale has
attributed to me.
 
D

Dave Vandervies

Dave Vandervies wrote:
It would be rather beyond the scope of a student project, but I would
expect that a sufficiently enthusiastic (or masochistic) C programmer
would be able to implement a Java compiler and JVM entirely in C
(though not the entire Java class library, but even there the parts
that don't have equivalents in C could be faked in C or passed on to
platform-specific extensions).

Except for the aforementioned bits of the class library that aren't
found in C, it would also be possible to write a Java-to-C compiler that
outputs standard C. (I don't know why anyone would bother, and it would
have a few Rather Ugly bits in both the translator and the generated C
(f'rexample, exception handling), but it could be done[1].)

Back in university I used to be involved in a (small part of a) project
that comes very close to what you describe, and your remark about
exception handling is right on the mark; so much in fact that back then
it was decided to target C++ instead of C to be able to piggyback on
C++'s exception handling.

Yep. C is interesting here in that it's too high-level to approximate
the way exceptions would be handled in a native-code implementation[2],
and too low-level to piggyback on an abstraction built into the language
(since the language doesn't have an appropriate abstraction).

setjmp and longjmp could be bludgeoned into useability for implementing
exceptions, but getting the appropriate information about what exception
occurred up the call stack would introduce some nasty complications.
The other obvious way to do it would involve checking whether you're
returning normally or throwing an exception (and handling it if you're
throwing an exception that's caught at that level) every time a function
returns, and even though the code generator does the hard work of writing
the code, I can't exactly see great efficiency gains being made by doing
it that way.

Funny thing: the compiler had no trouble
rewriting classes (including polymorphism, etc.) to C; only exception
handling was, well, exceptional.

Yep. Polymorphism is just an indirect function call through a pointer;
the cleanest way to do inheritance-that-adds-members requires some
mucking about with structs that isn't quite required to be legal (though
I think we once discussed it here and decided that there was no way it
could go wrong unless the implementation was actively checking for it,
because of the requirements that did exist on struct layouts), but that
can be worked around without getting too ugly.

Well, this is just saying that both are Turing-complete, basically. By
the same token you can say that Prolog can be implemented in COBOL and
vice versa.
Exactly.

I guess it would be fair to say that implementing C in Java
would have to involve some sort of simulation of 'untyped' memory, for
which Java doesn't have an equivalent.

Yep. Which is where the "Java can be implemented in C, but not the
converse" originally came from, if I haven't lost track.


dave


[1] Old footnote

[2] The obvious way to do it there would be to add an extra flag to
every stack frame and have the exception-throw handler unwind based
on those until it gets to the point where the exception is caught;
I almost did this for a simple compiler I wrote for a CS assignment
once[3].

[3] The language to be implemented had a poorly specified interaction
between looping and functions; the loop construct was a "loop until
a break is executed" and functions could be defined anywhere, and
one of the test cases was something like this:
--------
loop
{
function func()
{
break;
}
func();
}
--------
I did the obvious thing and didn't copy the compiler's internal
"break to" stack when I entered a function, so my compiler gave a
"break outside of loop" error here. The behavior the markers were
looking for was to break out of the loop here; after finding that
out, I thought about it for a bit and pointed out that the options
to correctly implement that behavior were to not use a stack at
all (contradicting a clarification I'd asked for earlier - local
variables in functions had to be reentrant) or to treat breaking as
throwing an exception and dynamically unwind the stack to the last
loop entered.
Apparently the simple (broken, or (at the most charitable) non-robust)
implementation was what they were looking for, but had I known
they'd be throwing that test case at it I'd've done it properly.
'Twouldn't've been hard, either, since most of the stack management
framework it would have needed was already built to handle other
things that it was already doing.
 
A

August Derleth

Richard said:
Think lazy. The minimum knowledge you can get away with is:

1) when you use a standard library function, look up the header it's
declared in, and make sure that header is included. For example, if you are
using printf, make sure you have this line:

#include <stdio.h>

2) when you are tempted to put a magic constant number in your code, use a
#define instead:

#define PI 3.14159

and use PI, rather than 3.14159, throughout your code. The preprocessor will
rip out the PI and replace it with 3.14159. PI, in this case, is not a
variable. It just becomes another way of writing 3.14159. As tradition has
it, this makes your program easier to modify, should the ratio of diameter
to circumference ever change.

You can also #define small bits of code that don't need to be in
functions but would be a massive pain to handcode each time.

For example, to access a specific value in an int that's actually a data
structure (maybe you got it from a function written in assembly language):

#define get_val1(x) (((x) & 0xF00) >> 8)

Let's parse that out:

#define get_val1(x) (((x) & 0xF00) >> 8)
^ ^ ^ ^ ^
1 2 3 4 5

1. The initial token that gets the preproecessor's attention.
2. The text of the macro. You type this, the preprocessor sees this, and
it gets replaced by what comes next. The C compiler never sees this.
3. The dummy variable. You never type this in the code; instead, you
type in the actual variable, which will replace every instance of the
dummy variable in the expanded code.
4. The replacement text. This is what the preprocessor dumps in after
it's replaced the text of the macro. The C compiler sees this.
5. The dummy variable, again. This will get replaced with the real one
by the preprocessor.

The preprocessor thereafter expands

x = get_val1(pdata);

to
x = (((pdata) & 0xF00) >> 8);

which is less readable, and shouldn't sully the eyes of a human with its
presence. :)

Some notes on doing this:

1. Don't expect typechecking or anything like that. The preprocessor
understands preprocessing tokens, not C. The expansion text will be
dropped in without regard to what the C compiler wants. That means you
shouldn't put semicolons after bits of #defined code.

1a. Always put parenthesis around the dummy variable in the expansion
put in the #define line. I wrote (((x) & 0xF00) >> 8) instead of
((x & 0xF00) >> 8) because somebody could call
get_val1(x + 3 << 8). I don't have a precedence table in front of me,
but that might not be parsed by the compiler the way I want it to be.
(Note that this is a side-effect from Rule 1 that deserves its own section.)

2. Don't abuse it. Having #define after #define modifying the source
code can render the final output unreadable (less of a concern, usually)
and possibly far from your actual intent (more of a concern).
 
L

LaDainian Tomlinson

I am a freshman computer science student teaching myself how to
program in C, since my university only teaches Java for the first
1.5 years. I have one or two (or 4) small questions, because I'm
finding C much more difficult than I did the first semester of
Java.

4) Any general advice for someone just starting out? Places to
go, people to see, etc.?

You've gotten plenty of good advice so far from real C experts, so
here's some from a fellow student. If you have the opportunity to take
a compiler construction course in your curriculum, it will be greatly
beneficial to your understanding of programming languages in general.
For C in particular, understanding exactly how things like pointers and
function calls are translated to machine code will make those concepts
much clearer. Although C syntax is usually fairly straightforward,
knowing how a grammar works can clear up syntax issues and help you
write more efficient code. Writing your own language (and a compiler
for it) is no small task, even if the language is (for example) a tiny
subset of C and you have a lot of tools to help, but it's really
rewarding to see source code turned into an actual executable. And
you'll have an enormous appreciation for gcc and perl once you finish!

Good luck,

Brandan L.
 
A

Arthur J. O'Dwyer

Pointers to functions can implement "methods", and be stored
within a struct. The usage is just somewhat different.

No, I'd say that my way is an implementation of "methods" with
different usage. What you're describing is an implementation of
"[some sort of] polymorphism" with the *same* usage (read: syntax)
but subtly different semantics. ;-)
What he may miss most is overloading.

Agreed. But you're not saying that what you're demonstrating here
is "overloading," are you? What language(s) call(s) it that?

typedef int (*addp) (int, int);
typedef struct foo {
int a, b;
addp add;
} foo, *foop;

int addarith(int a, int b) {return a + b;}
int addlogic(int a, int b) {return a ^ b;)

Using a sneaky font to compose news, huh? ^^^ should be }, not ).
foop makefoo(addp how, int av, int bv)
{
foop f;

if (f = malloc(sizeof *f)) {
f^.a = av;
f^.b = bv;
f^.add = how;

Geez, and I was complaining last week about the guy who was writing
under the influence of *Perl*! What sort of quiche-eating language
is *this*, pray tell? (-:
}
return f;
}

and now we can create foos that can add other foos in ways
specific to that foo.

foop fap = makefoo(addarith, 1, 1);
foop fbp = makefoo(addlogic, 1, 1);
foo fooresult;

foo addfoos(foop fa, foop fb)
{
foo fn;

fn = *fa;
fn->a = fa->add(fa->a, fb->a);
fn->b = fa->add(fa->b, fb->b);
return fn;
}

or something like that, assuming I have made no gross errors.

Looks pretty much good to me, except for the syntax errors.
Anyway, it displays one way to make a completely un-follow-able mess
of a C program. :) I don't think I've ever seen a really good use
for this sort of thing.
Results will be different between "fooresult = addfoos(fap, fbp)"
and "fooresult = addfoos(fbp, fap)".

Which will be a feature, of course. ;-)

BTW, I sympathize with the Trollsdale nonsense crossthread -- I
might not even have noticed the complete putting-words-in-mouth job
he did, if he hadn't inadvertently replaced the Pascal-influenced
syntax errors with completely original and Tisdale-influenced syntax
errors.

-Arthur
 
L

Lyn Powell

Keith Thompson said:
That's legal, but it's a bad idea to put data definitions in a header
file. Think about what happens if the same .h file is included from
two .c different files.

You can define i ("int i;") in one and only one .c file, and declare
it ("extern int i;") in the corresponding .h file.

(Better yet, avoid global data whenever possible.)

1) That was an example, not real code. But thanks for trying.
2) How is your example different from mine? As I understand it, C also
allows a model where only explicit initialization defines storage, and any
other declarations are just references. So both your example and mine will
still work, even though I do agree that data definitions are best left out
of a header file and I follow this reasoning in my real code.
 
D

Default User

Lyn said:
1) That was an example, not real code. But thanks for trying.

Examples to newbies are one of the WORST places to exhibit bad coding.
2) How is your example different from mine?

If you don't understand that, you shouldn't be giving advice, period. If
your headers are including in two different modules that are linked
together, your code will result in multiply-defined symbols. A very Bad
Thing.
As I understand it, C also
allows a model where only explicit initialization defines storage, and any
other declarations are just references. So both your example and mine will
still work, even though I do agree that data definitions are best left out
of a header file and I follow this reasoning in my real code.

What are you going on about? There are no models. What you had was bad
code. What Keith had was better, although as he himself pointed out,
probably not optimal. Newbies should stay away from globals until they
are experienced enough to know when the exceptions come into play, and
how to do things properly.



Brian Rodenborn
 
L

Lyn Powell

Default User said:
If you don't understand that, you shouldn't be giving advice, period. If
your headers are including in two different modules that are linked
together, your code will result in multiply-defined symbols. A very Bad
Thing.

Prove it. Give me line and verse from the C Standard that this is a valid
claim. If it is a "very Bad Thing" as you suggest, the Standard will say so.
What are you going on about? There are no models. What you had was bad
code. What Keith had was better, although as he himself pointed out,
probably not optimal. Newbies should stay away from globals until they
are experienced enough to know when the exceptions come into play, and
how to do things properly.

What I'm going on about is what I read from section 6.2.2 of the C99
Rationale and Standard. If I'm looking at the wrong section then tell me
where I should be looking so that I may clarify my understanding. But until
you prove to me, without a shadow of a doubt, that I'm wrong, I'll go by my
interpretation of the Standard.
 
A

Arthur J. O'Dwyer

Prove it. Give me line and verse from the C Standard that this is a valid
claim. If it is a "very Bad Thing" as you suggest, the Standard will say so.

FYI, Brian is another of those people to whom it's worth listening,
even though he doesn't succumb to the posting urge as often as some
other people. ;-) If he says it's a Bad Thing, he's probably right.
In this case, the Bad Thing goes as follows:

==file alpha.h==
int i;
==file alpha.c==
#include "alpha.h"
==file beta.c==
#include "alpha.h"
int main(void) { return 0; }
==end==

Cut-and-paste into three source files, and try to compile them and
then link them together. Whoops! Linker error!
Now try the "corrected" (but still bad style) version:

==file alpha.h==
extern int i;
==file alpha.c==
#include "alpha.h"
int i;
==file beta.c==
#include "alpha.h"
int main(void) { return 0; }
==end==

Ta-da! No linker error!
This aspect of the translation of C is covered in N869, section 6.9.2.

[#2] A declaration of an identifier for an object that has
file scope without an initializer, and without a storage-
class specifier or with the storage-class specifier static,
constitutes a tentative definition. If a translation unit
contains one or more tentative definitions for an
identifier, and the translation unit contains no external
definition for that identifier, then the behavior is exactly
as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of
the translation unit, with an initializer equal to 0.

-Arthur
 
S

Sidney Cadot

Arthur said:
[...snip...]
Now try the "corrected" (but still bad style) version:

==file alpha.h==
extern int i;
==file alpha.c==
#include "alpha.h"
int i;
==file beta.c==
#include "alpha.h"
int main(void) { return 0; }
==end==

Why is this still bad style?

Best regards,

Sidney
 
L

Lyn Powell

Arthur J. O'Dwyer said:
so.

FYI, Brian is another of those people to whom it's worth listening,
even though he doesn't succumb to the posting urge as often as some
other people. ;-)

I'm not good at trusting people's word without sufficient proof to back it
up.
This aspect of the translation of C is covered in N869, section 6.9.2.

[#2] A declaration of an identifier for an object that has
file scope without an initializer, and without a storage-
class specifier or with the storage-class specifier static,
constitutes a tentative definition. If a translation unit
contains one or more tentative definitions for an
identifier, and the translation unit contains no external
definition for that identifier, then the behavior is exactly
as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of
the translation unit, with an initializer equal to 0.

Thank you, that clears things up for me, I was looking in the wrong section.
You've shown me the wrong way, and a bad but valid way, what's the best way?
 
C

CBFalconer

Sidney said:
Arthur said:
[...snip...]
Now try the "corrected" (but still bad style) version:

==file alpha.h==
extern int i;
==file alpha.c==
#include "alpha.h"
int i;
==file beta.c==
#include "alpha.h"
int main(void) { return 0; }
==end==

Why is this still bad style?

He has this unreasoned instinctive fear and loathing of globals
and gotos :) He also omitted include guards.
 
A

Arthur J. O'Dwyer

I'm not good at trusting people's word without sufficient proof to
back it up.

That's fine. That's great, actually. I was just saying that even
though Brian's post was a little harsh, he *is* one of those people
who usually tells the truth. :) So if you see another of his assertions
that looks questionable, *look really hard* at the standard to make
sure you aren't missing anything, before making the assumption [as you
seemed to] that he [or anyone else, for that matter] must be mistaken.
(It's all about the tone.) Anyhoo...
Thank you, that clears things up for me, I was looking in the wrong section.
You've shown me the wrong way, and a bad but valid way, what's the best way?

CBFalconer explains here [this is a Message-ID header]
<[email protected]>
that not only was the header file missing inclusion guards [Google!]
but the program shouldn't have been using a global variable in the
first place. Especially not one named "i"!

HTH,
-Arthur
 
L

Lyn Powell

Arthur J. O'Dwyer said:
I'm not good at trusting people's word without sufficient proof to
back it up.

That's fine. That's great, actually. I was just saying that even
though Brian's post was a little harsh, he *is* one of those people
who usually tells the truth. :) So if you see another of his assertions
that looks questionable, *look really hard* at the standard to make
sure you aren't missing anything, before making the assumption [as you
seemed to] that he [or anyone else, for that matter] must be mistaken.
(It's all about the tone.) Anyhoo...

I'll try to watch my tone from now on. :)
Thank you, that clears things up for me, I was looking in the wrong section.
You've shown me the wrong way, and a bad but valid way, what's the best
way?

CBFalconer explains here [this is a Message-ID header]
<[email protected]>
that not only was the header file missing inclusion guards [Google!]
but the program shouldn't have been using a global variable in the
first place. Especially not one named "i"!

I see, so the issue was using a global variable in the first place, and lack
of inclusion guards. I thought I was missing something more subtle.
 
D

Default User

Arthur J. O'Dwyer said:
I'm not good at trusting people's word without sufficient proof to
back it up.

That's fine. That's great, actually. I was just saying that even
though Brian's post was a little harsh, he *is* one of those people
who usually tells the truth. :) So if you see another of his assertions
that looks questionable, *look really hard* at the standard to make
sure you aren't missing anything, before making the assumption [as you
seemed to] that he [or anyone else, for that matter] must be mistaken.
(It's all about the tone.) Anyhoo...

Hey, I'm nicer than Dan Pop! I wasn't really trying to be a jerk,
although I was in a strange mood yesterday. What I was trying to say was
that it seems as though Lyn doesn't have quite the experience base (that
means screwing up a lot, like multiply defining symbols and such) to be
giving out advice just yet. The instincts and desire seem to be there.

Learning C is a lengthy process. Most programmers reach a certain point
where they think they what's what. But they don't. Some never move from
that point, others reach enlightenment. For many (including me) it was
introduction to this newsgroup, wherein I found out how much I *didn't*
know. And still don't, for that matter. If I ever need to feel humble, I
need only read a Chris Torek explanation of something.

My suggestion would be to "answer in your head" and then see how that
matches up with what you read from the regulars. Ask about disconnects.

Also become familiar with CLC FAQ list:

http://www.eskimo.com/~scs/C-faq/top.html


For instance, the question at hand is covered pretty well in:

http://www.eskimo.com/~scs/C-faq/q1.7.html


At any rate, I hope Lyn will become a regular and valued contributor to
the newsgroup.




Brian Rodenborn
 
J

Joe Wright

Default said:
Arthur J. O'Dwyer said:
I'm not good at trusting people's word without sufficient proof to
back it up.

That's fine. That's great, actually. I was just saying that even
though Brian's post was a little harsh, he *is* one of those people
who usually tells the truth. :) So if you see another of his assertions
that looks questionable, *look really hard* at the standard to make
sure you aren't missing anything, before making the assumption [as you
seemed to] that he [or anyone else, for that matter] must be mistaken.
(It's all about the tone.) Anyhoo...

Hey, I'm nicer than Dan Pop! I wasn't really trying to be a jerk,
although I was in a strange mood yesterday. What I was trying to say was
that it seems as though Lyn doesn't have quite the experience base (that
means screwing up a lot, like multiply defining symbols and such) to be
giving out advice just yet. The instincts and desire seem to be there.

Learning C is a lengthy process. Most programmers reach a certain point
where they think they what's what. But they don't. Some never move from
that point, others reach enlightenment. For many (including me) it was
introduction to this newsgroup, wherein I found out how much I *didn't*
know. And still don't, for that matter. If I ever need to feel humble, I
need only read a Chris Torek explanation of something.

My suggestion would be to "answer in your head" and then see how that
matches up with what you read from the regulars. Ask about disconnects.

Also become familiar with CLC FAQ list:

http://www.eskimo.com/~scs/C-faq/top.html

For instance, the question at hand is covered pretty well in:

http://www.eskimo.com/~scs/C-faq/q1.7.html

At any rate, I hope Lyn will become a regular and valued contributor to
the newsgroup.
Brian. I want to commend you and Arthur for being so nice to Lyn. Is it
because you think Lyn is a girl? How about Leonard Powell? Would you be
so nice? I suppose so. I think Dan Pop is ever so nice.
:)
 

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,135
Messages
2,570,783
Members
47,341
Latest member
hanifree

Latest Threads

Top