Another spinoza challenge

K

Keith Thompson

bartc said:
Surely it's only convention that stops you using _MAX_POWER in
ordinary programs. At the level of the tokeniser in a C implement,
it's just an identifier, and not a keyword or anything else.

Sure, if you consider the C standard to be "only convention".

A conforming C implementation could have _MAX_POWER as a keyword.
A C program that declares something with the name _MAX_POWER, in
the absence of specific permission from a particular implementation,
has undefined behavior.
 
J

jameskuyper

bartc said:
Surely it's only convention that stops you using _MAX_POWER in ordinary
programs. At the level of the tokeniser in a C implement, it's just an
identifier, and not a keyword or anything else.

Nothing stops you from using _MAX_POWER in C code; there are simply
inconvenient consequences if you choose to do so, and Keith has
correctly, and I believe completely, summarized those consequences
are. A conforming C compiler may choose to reject your code, or to
accept it. If it accepts it, your program has behavior that is
defined, if at all, only by your implementation, not by the standard.
Whether that behavior is undefined, or merely defined by your
implementation, it might be quite different from what you might have
expected it to be. If those consequences are acceptable to you, you're
perfectly free to use _MAX_POWER.
 
K

Keith Thompson

jameskuyper said:
Nothing stops you from using _MAX_POWER in C code; there are simply
inconvenient consequences if you choose to do so, and Keith has
correctly, and I believe completely, summarized those consequences
are. A conforming C compiler may choose to reject your code, or to
accept it. If it accepts it, your program has behavior that is
defined, if at all, only by your implementation, not by the standard.
Whether that behavior is undefined, or merely defined by your
implementation, it might be quite different from what you might have
expected it to be. If those consequences are acceptable to you, you're
perfectly free to use _MAX_POWER.

You're equally free to terminate all your declarations and statements
with dollar signs rather than semicolons, with almost exactly
the same range of possible consequences. The only qualititative
difference is that a diagnostic is required. (Admittedly using
dollar signs is far more likely to cause your program to be
rejected.)
 
F

Flash Gordon

John said:
Here is the context from the quiz:

I was aware of the context.
Which variable names are valid?

[] Int [] Xsquared
[] no! [] point_3
[] 20t [] _MAX_POWER
[] bc+a [] array(size)
[] char [] array size

In this context, _MAX_POWER is valid for the same reasons Int,
Xsquared, and point_3 are valid. The quiz (which is mostly rubbish)
is written at a first-grade level; concepts such as "reserved for the
implementation" are well beyond its scope.

At a beginner level I would say it was better to state that you (the
learner) are not allowed to use names beginning with an underscore.
Later on the rule can be relaxed to say, well, you can use them where
your documentation specifically allows (or requires) them. Easier, IMHO,
than starting off believing simply that you can use them and later
finding that most of the time you can't.
 
P

Phil Carmody

Keith Thompson said:
This entire debate is about the meaning of the phrase "valid
identifier". Since the standard does not provide a definition for
this phrase (it defines what an "identifier" is, but not what a
"valid identifier" is), I don't believe it's possible to reach any
real conclusion.

Alas, that's a bit of a GEB-esque. If the English language, the
language in which the standard is written, defines meanings for
'valid', which it does, then it's perfectly fair to apply those
definitions to concepts mentioned in the standard. You will hopefully
note that the standard does not define every single word used
therein. One can only conclude that it leaves words not specifically
defined in the domain of the base language. 'Valid' falls within
that shroud.
_MAX_POWER is certainly an identifier. An implementation is free
to define an entity called _MAX_POWER. Given an implementation that
defines such an entity, a program for that implementation is free to
use it in accordance with the implementation's documentation. Such a
program is not portable.

In what way is the following not portable?

#if defined _MAX_POWER
# define foobarbaz 0
#else
# define foobarbaz 0
#endif
int main(/*elided...

The behavior of a program that defines an
entity called _MAX_POWER is

not brought into consideration, by myself, at least.
, in general, undefined, though it may
be defined for a particular implementation if that implementation,
for some reason, allows programs to define such an entity.

I believe the above summarizes everything the C standard has
to say about the identifier _MAX_POWER (though I could have
missed something). And I still don't know whether it's a "valid
identifier". That suggests that it's a meaningless question

Again, we're in agreement.
unless you define exactly what the phrase "valid identifier" means.
Feel free to provide your own definition and use it to answer the
question -- but don't expect everyone else to accept your conclusion.

42

Phil
 
P

Phil Carmody

Richard Heathfield said:
bartc said:

Absolutely. Tests *should* be pedantic.

I'm not so sure. Or perhaps I am.

I clearly remember my Trinity College interview way back where
I repeatedly used the word "weight" in the presence of the
college's applied maths tutor, and he kept "correcting" me to
use the word "mass" given the context in which I was using it.

He was of course wrong. And I'm prepared to summon Usenet's
units troll if anyone dare disagree.

Phil
 
P

Phil Carmody

Kenneth Brody said:
It appears that some people can't grasp the fact that passing a
variable by reference, and passing the address of a variable by value
are not the same thing. (Yes, you can achieve the effect of changing
the caller's variable's value by doing pointer-by-value, but that
doesn't make them the same thing.)

It appears that some people can't grasp the fact that one can
effect pass by reference by passing variables by address.

Phil
 
B

Ben Bacarisse

spinoza1111 said:
...and now for something very different...

Here's a better test.

I don't think so. I thought long and hard about replying at all, but
there is enough misinformation in both the test and your answers that
at least a correction of facts should be posted.


The test is dated 1997 and uses a version of that was out of date even
then. Historical tests are fine, but this fact affects some of the
answers so the read should keep this in mind.

***** Argument coercion: Suppose your routine receives an unsigned
long as its argument, but you
***** need to use it as an integer. How would you coerce it?

If safety is not a concern I would use "coercion" aka "casting" as in
(int)ulngValue. If safety is a concern I would test the coercion like
this:

intValue = (int)ulngValue;

If the conversion is unsafe the game is up when you do this.
if ((unsigned long)intValue != ulngValue) printf("Error\n");

You should test against the int type's limits:

if (ulngValue > INT_MAX) /* report a problem... */
***** Sending functions as arguments: Suppose your routine receives a
pointer to a function as its
***** first argument, as in the example

***** routine (foo, n);
***** int foo ();
***** int n;
***** { ... code ... }

There is a syntax error in the question.
***** How will the code invoke that function, passing it the integer
value as its single argument?

(*fooInstance)(n); // Don't know if this is right. Have added possibly
redundant parentheses.

(The name is wrong, but if you use * the parentheses are not
redundant. *foo(n); is entirely different to (*foo)(n);).

The age of language being discussed matters here. My guess is that
the expected answer is

(*foo)(n);

For nearly 20 years another, possibly better, answer has been

foo(n);

and anyone learning C now should remember that both work and mean the
same thing.
***** Declarations and typedefs
***** How would you define a type num_ptr, that is a pointer to an
integer?

typedef num_ptr int *;

typedef int *num_ptr;
***** How would you define a type num_array, that is a pointer to an
array of 100 integers?

typedef num_array int[100] *;

typedef int (*num_array)[100];

Note: this is an unusual type in C and I suspect that the test author
did no mean to ask for it, but who can tell?
***** How would you define a type complex, that is a structure for a
complex number (containing two
***** part, real and imag, each of which is a double)?

struct complex
{
double realPart;
double imagPart;
} [instance name is optional here if you want to declare an instance
here] ;

typedef struct complex { double real, imag; } complex;
***** Forward declarations: Under what circumstances do you need to
make a forward declaration of a
***** function? Any other data type?

You need to do a FD when a function refers to another function in the
same compilation unit, and for some sillyass reason the function
implementation needs to follow the reference. Unlike many decent
languages, C requires the programmer to define all symbols before they
are used; this in itself shows that C is an antique, since memory in
older machines was at a premium. If the text of the function follows
its use, the header of the function must be coded as a semicolon-
terminated C statement before the first use. This is because the
correct parsing of a function use requires knowledge of its
declaration, as in the case of a function with a variable number of
arguments.

Given the age of the C being discussed, a lot of this answer is wrong
(some of it is wrong about modern C as well) and a correct answer
would be of only historical interest.
***** C declarators: Typedefs and declarations are two instances of C
statements that
***** use "declarators"; typecasts also do. What is x, according to
each of the following
***** declarators?

int *x; a pointer to an integer
int *x(); a pointer to a function that returns an integer

a function returning a pointer to int
int **x; a pointer to a pointer to an integer
int **x(); a pointer to a pointer to a function that returns an
integer

a function returning a pointer to pointer to int
int *x[10](); a pointer to a function that returns an array of ten
integers

In this case the type of x is not a valid C type. Literally
transcribed it is "and array of 10 functions returning poiter to int"
but this is not allowed in either C90 or C99. Of the test is about
K&R C and I had to go check to see if there was a special rule about
this type in old C. There isn't. It was not valid in K&R C either.
***** (Hint: don't be too sure you know, unless you are aware of the
so-called right-left rule for C ***** declarators.) If you're really
confident, what is
int *(*(*(*x)()) [10]) ();

I don't have the confidence to figure this one out. As code it sucks.

Yes, it's a silly type: "a pointer to function returning pointer to array
of 10 pointers to functions return pointer to int" (I think).
But you know that.
Skipped.

***** This is from Harbison/Steele, p. 83.
***** Structures and unions
***** Structure names: Is it wrong for a to appear twice in this
declaration? Explain
***** struct a {int num1, num2;} a;

No, since the structure name a is prefixed when it is used by
"struct". C knows that "a" is a structure when it is used as a
structure because it must be prefixed by "struct". Of course, it is
very poor practice to do this. Disciplined use of Hungarian notation
(TYP for the structure, USR for a structure instance) avoids this.

Anyone learning c should know that this latter opinion is not
universally held.
***** Padding of structures: Why is the size of the following two
structures different? How would
***** you prove it?

It would be better to ask why might they be different since they don't
have to be. In fact, I guess the are quite often are the same size (they
are on my current laptop).
***** struct y {double big;
***** float med; int small;
***** char tiny; char tiny2};

There is a syntax error in this question as well.
***** struct z {double big;
***** char tiny; float med;
***** char tiny2; int small;};
The sizes are different because in the second, "med" is aligned on a
word (32 bit) boundary, resulting in three extra pad bytes after tiny,
and small is aligned on a halfword binary, resulting in an extra byte
after tiny2.
Prove it by coding and running this:

struct y yInstance;
struct z zInstance;
printf("Struct y len=%d: struct z len=%d\n", &(structyInstance.tiny2)
+ sizeof(char) - &yInstance,&(structzInstance.small) + sizeof(int) -
&yInstance);

There are too many typos to know what was intended here but it is
overly complex. If the typos are just in the variable names, then n
the code in undefined unless there is are one or #defines in effect
that fix the problems.

A simpler solution is:

printf("struct y and struct z are%s the same size.\n",
sizeof(struct y) == sizeof(struct z) ? "" : " not");
 
B

Ben Bacarisse

Ha! I decided to cancel this post but then accidentally sent it part
finished. Given that error, I may as well finish it now:

Ben Bacarisse said:
spinoza1111 <[email protected]> writes:

It would be better to ask why might they be different since they don't
have to be. In fact, I guess the are quite often are the same size (they
are on my current laptop).


There is a syntax error in this question as well.


<snip one possible layout>

At this point I gave up, but had I gone on I would have had to remove
this snip and comment on the fact that the end padding may be more
important than any in the middle, though it is all system specific.

On my system I can only prove it is not so.
There are too many typos to know what was intended here but it is
overly complex. If the typos are just in the variable names, then n
the code in undefined unless there is are one or #defines in effect
that fix the problems.

A simpler solution is:

printf("struct y and struct z are%s the same size.\n",
sizeof(struct y) == sizeof(struct z) ? "" : " not");

It is likely that the question was supposed to be about the layout of
structs rather than the size of them, but that is just a guess.

Lots of other answers are possible, of course.

<snip>
 
S

spinoza1111

spinoza1111said:



I don't see what "pass by reference" is doing in a C test, since C
doesn't do pass by reference.

That's absurd. It's an example of your computing Fundamentalism which
licenses C "experts" to be ignorant of computer science.
So the answer to "What is the
difference between the way you declare an integer that is passed by
reference and one that is passed by value?" is that the second is
easy and the first is impossible, and the follow-on question is
meaningless.

Nonsense on stilts. We all know that C's "call by reference" is
virtual, and supported by stacking the VALUE of a von Neumann address,
therefore at the level of the runtime machine, call by reference
becomes call by value. But how else would one implement call by
reference, save by some idiot procedure such as stacking the entire
target, letting the called procedure have at it, and then copying it
back?

Howsoever implemented, call by reference is a valid call method which
needs a name. Does C unleashed use something else such as "call by
address" or "call by fanorkle"?

You destroy the English language when you disallow imagination and
creativity. You're nothing more than one of those irritating garden
gnomes who sit in companies and destroy them, while snarling at people
about "terminology".

Care to find a better test?

Shall I record your grade as zero?
 
S

spinoza1111

I'm not so sure. Or perhaps I am.

I clearly remember my Trinity College interview way back where
I repeatedly used the word "weight" in the presence of the
college's applied maths tutor, and he kept "correcting" me to
use the word "mass" given the context in which I was using it.

He was of course wrong. And I'm prepared to summon Usenet's
units troll if anyone dare disagree.

Phil
--
If GML was an infant, SGML is the bright youngster far exceeds
expectations and made its parents too proud, but XML is the
drug-addicted gang member who had committed his first murder
before he had sex, which was rape. -- Erik Naggum (1965-2009)- Hide quoted text -

- Show quoted text -

Others apart sat on a hill retired,
In thoughts more elevate, and reasoned high
Of Providence, Foreknowledge, Will, and Fate--
Fixed fate, free will, foreknowledge absolute,
And found no end, in wandering mazes lost.

(Milton, Paradise Lost)
 
D

Dennis \(Icarus\)

Flash Gordon said:
The point I was driving at is that a specific implementation allowing
something beyond the C standard does not make a it valid beyond that
implementation, so a general statement it is valid is not appropriate.

It's a variable, and the name is syntactically valid.
An implementaion can do
#define _MAX_POWER 32
In which case you cannot use _MAX_POWER as a variable on that
implementation. Do you agree with that? If so, that shows that apart

Of course.
from specific implementations which document _MAX_POWER as being allowable
for a variable, it is not valid, because it might lead you to having
(after macro expansion
int 32;
So in general it is not valid, and that is important for a test which is
not about a specific implementation.

Remember, the question simply asked about valid identifiers.
It should be pretty clear that it is, reserved for the implementation
because of the leading _, but it is a valid identifier.
Can you see now why a reasonable interpretation of the word "valid" would
lead to consider _MAX_POWER as not being valid?

Onky if you read in more that what is being asked.
I've never said it is the ONLY possible interpretation, only that it is a
reasonable one.


You get very strange things in system headers, so no I would not feel safe
using that.

Ok.

Dennis
 
P

Phil Carmody

Richard Heathfield said:
Phil Carmody said:


Only by torturing the concept of pass by reference beyond its yield
point.

Not in my opinion.
If passing the address of a variable were equivalent to
passing by reference, then the following program would print 42:

Strong assertion.
#include <stdio.h>

void byref(int *p)
{
p = 42; /* bug - p was *not* passed by reference. */
}

And completely unfounded. There's no definition of 'pass by reference'
which would justify your claim. You've just burnt a straw man.
[Snip things dependenent upon straw man.]

Phil
 
K

Keith Thompson

Phil Carmody said:
Richard Heathfield said:
Phil Carmody said: [...]
It appears that some people can't grasp the fact that one can
effect pass by reference by passing variables by address.

Only by torturing the concept of pass by reference beyond its yield
point.

Not in my opinion.
If passing the address of a variable were equivalent to
passing by reference, then the following program would print 42:

Strong assertion.
#include <stdio.h>

void byref(int *p)
{
p = 42; /* bug - p was *not* passed by reference. */
}

And completely unfounded. There's no definition of 'pass by reference'
which would justify your claim. You've just burnt a straw man.
[...]

The point, I think is that *just* passing the address of a variable
is insufficient to implement passing by reference in C.

To implement or emulate pass by reference in C, you have to (a)
pass the address of the object you want to pass by reference, and
(b) make sure that every reference within the function is explicitly
dereferenced.

In languages that actually do implement pass by reference, you can
just pass the name of the object as an argument, and refer to the
parameter by name inside the function.
 
B

bartc

Richard Heathfield said:
Phil Carmody said:


Only by torturing the concept of pass by reference beyond its yield
point. If passing the address of a variable were equivalent to
passing by reference, then the following program would print 42:

#include <stdio.h>

void byref(int *p)
{
p = 42; /* bug - p was *not* passed by reference. */
}

int main(void)
{
int i = 6;
byref(&i);
printf("%d\n", i);
return 0;
}

Instead, the above provokes a diagnostic message (and rightly so).

Now try this variation:

#include <stdio.h>

struct point{int x,y;};

void byref(struct point *p)
{
p.x = 42; /* bug ??? */
}

int main(void)
{
struct point i = {6,7};
byref(&i);
printf("i.x = %d\n", i.x);
return 0;
}

Again this gives an error, because it should be p->x in byref to properly
dereference p.

Yet some here are proposing that the compiler should silently convert p.x to
p->x (automatic dereference). In this case, pass-by-reference would become a
reality.
 
N

Nick Keighley

Often for its own internal use.

I use __LINE__ in my code
Such as symbols which are in headers so
it can use them in macro implementations of library functions. Ones the
implementation documents as available for you to use are valid for that
specific C implementation, but not valid in general. The test did not
specify a specific implementation, so for anything to be valid it has to
be valid across at least the range of conforming hosted implementations.

for it to be "valid" they have to define what "valid" means.
 
N

Nick Keighley

Alas, that's a bit of a GEB-esque.

Great Endorian Barbeque?
If the English language, the
language in which the standard is written,

It isn't really written in english. It uses a highly specialised
vocabulary.If "valid" were used I'd expect a careful definition
of it.


defines meanings for
'valid', which it does, then it's perfectly fair to apply those
definitions to concepts mentioned in the standard. You will hopefully
note that the standard does not define every single word used
therein. One can only conclude that it leaves words not specifically
defined in the domain of the base language. 'Valid' falls within
that shroud.
<snip>
 
B

Ben Bacarisse

Richard Heathfield said:
bartc said:



Yes, bug.


And in any case what is actually passed is a value.


Right, *if* they can persuade ISO to muddy the waters in that way.

K&R muddied the waters themselves. bartc should have illustrated the
point with an array rather than a hypothetical struct syntax:

#include <stdio.h>

void byref(int v[])
{
v[0] = 42;
}

int main(void)
{
int vec[] = {1, 2, 3};
byref(vec);
printf("vec[0] = %d\n", vec[0]);
return 0;
}

This passes almost every test for "pass by reference" one can think
of. There is no special syntax in the called function and none
needed at the point of call. The parameter declaration can even look
like an array.

The only test it fails is that C does not have pass by reference!
 
S

spinoza1111

spinoza1111said:



There is a huge difference between pass-pointer-by-value and
pass-object-by-reference. I have just spent some time explaining this
difference in a reply to Phil Carmody, to which reply I draw your
attention.

Richard, you appear to be ignorant of how to write runtime code.
No, it's an example of knowing what pass-by-reference means.



Your "knowing" it doesn't make it so.


Absolutely - and we can call it "call by reference", but C doesn't
have it and therefore does not need a name for it.


As far as I can recall (but it's a large book with several authors so
I could be wrong), it doesn't use the "call by..." construct at all.
What would be the point? Counter-examples to the usual address,
please (by value).


None of us has the power to destroy the English language, so you are
indulging in hyperbole. Furthermore, whilst imagination and
creativity are wonderful concepts, they are not necessarily useful in
resolving terminology disputes.

They are, because you're not talking about a scientific matter in the
last analysis, despite your fantasies. You're talking about human
language and behavior around computers.
I think you mean the test you found was broken - again.

It appears to me that any test you can't pass, you don't like.
I'm not interested in taking broken tests.

I shall record your grade as zero.
 
S

spinoza1111

Phil Carmody said:





Only by torturing the concept of pass by reference beyond its yield
point. If passing the address of a variable were equivalent to
passing by reference, then the following program would print 42:

#include <stdio.h>

void byref(int *p)
{
  p = 42; /* bug - p was *not* passed by reference. */

}

So, for you, pass by reference means that the unadorned variable in
the source code means, when passed by reference, its changeable value
in the namespace of the caller. This is the case in Visual Basic, but
VB doesn't presume to control.

Sure, to modify a variable set up as what is commonly referred to as
"by reference" in C, you must use a special notation. This is a
limitation of C, since the fact that you have to dereference gives you
a false power, eg., you can also get the address, and REALLY screw
EVERYTHING up.

Nonetheless, most C programmers call passing the variable with the
asterisk in the formal parameters as "by reference".
 

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
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top