References in C

J

Jens Thoms Toerring

jacob navia said:
Le 24/06/11 15:26, Shao Miller a écrit :
Yes. You must pass an object, not a pointer.

Just out of curiosity: how are things handled if there's no
declaration for the function that expects a reference argument
has been seen by the compiler? Since it's legal not to have a
function prototype (or one that doesn't specify the arguments)
how does the compiler figure out in that case if it has to pass
a pointer or the structure itself when all it sees is

struct xxx bar;
foo(bar_ptr);

Or do you have some constraint that functions expecting refe-
rences can only be used when a full prototype has been seen?

Regards, Jens
 
S

Shao Miller

The "partly" refers to the fact that an initialized local const
pointer object, as long as the initialization isn't a null pointer,
will always point to the same thing, but no such guarantees can be
made for a pointer parameter unless you use the C99 "static" kludge.

I don't understand why:

void foo(int * const ip);

couldn't give the same guarantee, assuming the point is that 'ip' within
the function definition for 'foo' mustn't be modified; "point to the
same thing," even if "no thing," which is a different point.
 
J

jacob navia

Le 24/06/11 22:33, Shao Miller a écrit :
If lcc-win references become standard C, if I have:

#include <assert.h>
#include <stddef.h>

#define ELEMENTS 5
#define COUNTOF(array) \
(sizeof (array) / sizeof *(array))

typedef double a_five_doubles[ELEMENTS];

void foo(a_five_doubles & array) {
size_t i;

for (i = 0; i < COUNTOF(array); ++i)
array = 3.14159;
return;
}

int main(void) {
a_five_doubles array;

foo(array);
return 0;
}

Does the 'for' loop execute five times? I'm guessing that C99's
6.3.2.1p3 and 6.7.5.3p7 would need to be adjusted, right? (My C++ memory
for this is poor, I'm afraid, if that's relevant here.)


That should work OK, sizeof a_five_doubles should be 40, and actually
only the address of the array is passed.

That doesn't work OK NOW because lcc-win has a bug when taking the
reference to an array. That will work OK tomorrow when I correct
that bug :)

jacob
 
J

jacob navia

Le 24/06/11 22:44, Jens Thoms Toerring a écrit :
Just out of curiosity: how are things handled if there's no
declaration for the function that expects a reference argument
has been seen by the compiler?

lcc-win is one pass compiler. No references are assumed, and
when the prototype is seen an error occurs: redefinition
of "foo" previously defined at line such and such.

Since it's legal not to have a
function prototype (or one that doesn't specify the arguments)
how does the compiler figure out in that case if it has to pass
a pointer or the structure itself when all it sees is

struct xxx bar;
foo(bar_ptr);

Or do you have some constraint that functions expecting refe-
rences can only be used when a full prototype has been seen?

Regards, Jens

Of course if this is going to work you must write a prototype!
Or pay me a special fee so that I introduce a special case
in the compiler:

if (isJensThomsToerring(currentUser) && !strcmp(functionName,"foo")) {
// pass by reference
}

:)
 
K

Keith Thompson

Shao Miller said:
I don't understand why:

void foo(int * const ip);

couldn't give the same guarantee, assuming the point is that 'ip' within
the function definition for 'foo' mustn't be modified; "point to the
same thing," even if "no thing," which is a different point.

foo(NULL);

I should have been clearer that "the same thing" refers to some object.
 
I

Ike Naar

Error prone how? Aside from the typo which was easy enough to fix.
If I have a complicated function in which I want to work on it by
reference this is how I would do it. of course I'd switch the names
around so the frequently used one was shorter...

My error was akin to

int foo(int &bar)
{
return (baz *= 3);
}

It's a friggin typo, not a design error.

The problem with macro tricks is they always frig.
They are, so, to say, error prone. See below:

void increment(int *x) /* uses the call-by-reference macro trick */
{
#define refx (*x)
++refx;
}

void use_increment(void) /* using above function */
{
int i = 42;
increment(&i);
if (i == 43)
{
/* got here */
}
}

/* so far so good */

/* ... 99999 more lines of code ... */

/* The author of ``is_null'' is unaware of the
fact that the name ``refx'' was #defined 100017 lines earlier.
*/
int is_null(char *refx) /* looks like an ordinary parameter */
{
return refx == NULL;
}

void surprise(void)
{
if (is_null(NULL))
{
/* Expected to get here, but got a segfault instead */
}
}

In isolation, the functions ``increment'' and ``is_null'' are both
harmless and unsurprising; but the macro definition in ``increment''
has an unexpected and devastating effect on the working of ``is_null''.

Of course the code is a bit contrived, but I hope you get the point:
macro tricks are best avoided, or at least one should be careful.
For instance, adding ``#undef refx'' at the end of ``increment'' would
have made a difference.
 
B

Ben Bacarisse

jacob navia said:
Le 24/06/11 22:44, Jens Thoms Toerring a écrit :


lcc-win is one pass compiler. No references are assumed, and
when the prototype is seen an error occurs: redefinition
of "foo" previously defined at line such and such.

That's not what happened when I tried it. I got a run-time exception.
Probably my version is too old (3.8).

BTW, "one pass" does not mean you can't go back and patch up or revise
prior definitions and so on. It just means the source is read once.

Second BTW: I don't think it's an error to see a prototype for a
previously un-prototyped function (I've not checked the standard but
modulo a few details about composite types and promoted arguments I
think it's correct). Obviously, you can introduce new rules for
references since they are not standard C, but the version of lcc I have
correctly does not complain about this (although the output is wrong):

#include <stdio.h>

void f();

int main(void)
{
f(&(int){42});
return 0;
}

void f(int *ip)
{
printf("%d\n", *ip);
}

<snip>
 
B

BartC

Joe Wright said:
On 6/24/2011 17:09, jacob navia wrote:

[ Snipping everything }

What advantage does C++ reference have? None say I. Pass &var and accept
*var and all is solved simply. Tell me where I'm wrong.

I think the big thing is the implicit dereferencing. Let's say you have a
piece of code, for example:

a+=2;

and wanted to put this into a function. With references, it might look like
this:

void addtwo(int &a){
a+=2;
}

and is called as:

addtwo(a);

Notice the code in the function can be exactly the same: no "*" is needed
(plus checks for NULL) and no "&" is needed to pass the value to be
modified, so no need to write:

a=addtwo(a);

or:

addtwo(&a);
 
I

Ian Collins

On 6/24/2011 17:09, jacob navia wrote:

[ Snipping everything }

What advantage does C++ reference have? None say I. Pass&var and accept
*var and all is solved simply. Tell me where I'm wrong.

For one, you don't have to test for NULL, for another you don't have to
clutter up your code with *& and *.

The case for references in C isn't as strong as it is for C++, where
references are required for operator overloading.
 
J

Jens Thoms Toerring

jacob navia said:
Le 24/06/11 22:44, Jens Thoms Toerring a écrit :
lcc-win is one pass compiler. No references are assumed, and
when the prototype is seen an error occurs: redefinition
of "foo" previously defined at line such and such.
Of course if this is going to work you must write a prototype!

Thanks, I see.
Or pay me a special fee so that I introduce a special case
in the compiler:
if (isJensThomsToerring(currentUser) && !strcmp(functionName,"foo")) {
// pass by reference
}

Sorry but not likely to happen in the near future;-)

Regards, Jens
 
N

Nick Keighley

I can't see a reason to not have it, but just the same I can't say
that my programming career has been taking back by it.  What I would
love is Turbo Pascals "with" stmt.  e.g.

eek!!!!!!!! just as microsoft didnt invent basic so borland didnt
invent pascal. 'with' is actually a standard pascal feature

I understand 'with' presents problems and this is one reason it hasnt
been widely adopted
 
B

BGB

eek!!!!!!!! just as microsoft didnt invent basic so borland didnt
invent pascal. 'with' is actually a standard pascal feature

I understand 'with' presents problems and this is one reason it hasnt
been widely adopted

in my own language, I have "with", but IIRC it was inherited from the
languages it was based on (JavaScript and ActionScript).

however, as-implemented, using with will currently temporarily redirect
"this", meaning that bindings located in the real "this" are temporarily
inaccessible.

there is no ideal solution, apart from temporarily creating a new
temporary binding to hold the old "this", and internally redirecting any
field accesses to it (but, this itself has issues, for example, the old
'this' would then have tighter binding than the newly-added "this",
which has a binding precedence weaker than that for locals and
arguments). exiting the "with" then restores the original "this".

but, yeah, there are other issues as well...


also, a lot of these sorts of constructions will mix poorly with the use
of goto (using goto in some places may risk causing some very strange
behaviors, although later the compiler may check for an raise an error
regarding use of goto into/out of some constructions, such as
"with"/"package"/"class"/try-catch blocks/...).

granted, yes, these are not likely to be an issue in sanely-written code...
 
I

Ian Collins

in my own language, I have "with", but IIRC it was inherited from the
languages it was based on (JavaScript and ActionScript).

however, as-implemented, using with will currently temporarily redirect
"this", meaning that bindings located in the real "this" are temporarily
inaccessible.

there is no ideal solution, apart from temporarily creating a new
temporary binding to hold the old "this", and internally redirecting any
field accesses to it (but, this itself has issues, for example, the old
'this' would then have tighter binding than the newly-added "this",
which has a binding precedence weaker than that for locals and
arguments). exiting the "with" then restores the original "this".

but, yeah, there are other issues as well...

also, a lot of these sorts of constructions will mix poorly with the use
of goto (using goto in some places may risk causing some very strange
behaviors, although later the compiler may check for an raise an error
regarding use of goto into/out of some constructions, such as
"with"/"package"/"class"/try-catch blocks/...).

granted, yes, these are not likely to be an issue in sanely-written code...

Any sanely designed language wouldn't have goto!
 
B

BGB

Multi-level loop break/continues.

yeah. JavaScript and ActionScript also have "break label;" and "continue
label;", which as I see it are mostly just glorified gotos (or glorigied
multi-level break/continue, either way, as break/continue are themselves
internally implemented as gotos...).

my language includes these as well...

so:
break 2; //break 2 levels
break FOO;
goto FOO;

are all technically valid.

I personally see little wrong with including goto, as it may have uses
in some cases, although it is very rarely used in my own code.


also planned is, possibly say:
x=&&FOO;
goto *x;
for a computed goto.

but, I have not yet implemented this (not a high priority).


or such...
 
D

Dr Nick

Nick Keighley said:
I understand 'with' presents problems and this is one reason it hasnt
been widely adopted

It exists in the templating language ClearSilver. I haven't used it
much, but on the odd occasions I have it's served to remove huge piles
of repeated this[that].other[perhaps].something in a block of code.

ClearSilver is carefully designed to prevent you doing too much of the
programming in it and to prevent endless loops. I don't know if that
helps to work around the problems you allude to.
 
S

Shao Miller

Any sanely designed language wouldn't have goto!

I must respectfully disagree. :) I usually employ it for clean-up purposes.

Having said that...

/* "So you don't like goto, eh?" */

#include <stdlib.h>
#include <stdio.h>

int main(void) {
enum {
DONE,
FREE_MEM,
FREE_MORE,
START
} state = START;
char * foo, * bar;

do switch (state) {
default:
puts("Invalid state!");
state = DONE;
continue;
case START: state = DONE;

/* Allocate foo. */
foo = malloc(12);
if (!foo) {
puts("No foo!");
continue;
case FREE_MEM:
free(foo);
puts("Freed foo.");
state--;
continue;
}
puts("Allocated foo.");
state++;

/* Allocate bar. */
bar = malloc(12);
if (!bar) {
puts("No bar!");
continue;
case FREE_MORE:
free(bar);
puts("Freed bar.");
state--;
continue;
}
puts("Allocated bar.");
state++;

/* All done. Free resources or return, as you wish. */
puts("Done.");
} while (state);
return EXIT_SUCCESS;
}
 
B

BartC

Shao Miller said:
On 6/24/2011 17:09, jacob navia wrote:

[ Snipping everything }

What advantage does C++ reference have? None say I. Pass&var and accept
*var and all is solved simply. Tell me where I'm wrong.

For one, you don't have to test for NULL,

(By which you obviously mean a null pointer value. I don't use 'if (p ==
NULL)' but 'if (!p)'.)

But I still don't fully perceive this particular benefit, here.

The benefit (as I understand it) is that the code doesn't even need to be
aware that something is a pointer:

a = b+c*d;

instead of:

if(a && b && c && d) *a=*b+*c*(*d);
else ... /* big headache... */
 
S

Shao Miller

On 6/24/2011 17:09, jacob navia wrote:

[ Snipping everything }

What advantage does C++ reference have? None say I. Pass&var and accept
*var and all is solved simply. Tell me where I'm wrong.

For one, you don't have to test for NULL,

(By which you obviously mean a null pointer value. I don't use 'if (p
== NULL)' but 'if (!p)'.)

But I still don't fully perceive this particular benefit, here.

For "static" and "automatic" objects, if you pass '&x', there can be
little doubt that the called function gets a valid "reference" to an
object. This can be observed at translation time.

For "allocated" objects, if we check for allocation success (not
everyone does, of course), then there should be no doubt about having a
valid object reference.

Please consider:

void func(int & i) { /* ... */ }

If we have some pointer ('int * ip') with a null pointer value and we do:

func(*ip);

do we not simply move the point of failure up to the caller? Whereas with:

void func(int * ip) { /* ... */ }

and:

func(ip);

if 'func' doesn't check for a null pointer value, the point of failure
is simply with the callee?

Either way, the program fails. This can't be observed at translation
time, with or without references, right?

It reminds me of "cdecl" where the caller takes responsibility for
something.
for another you don't have to
clutter up your code with *& and *.

Agreed. It's especially annoying for arrays.

void func(char (* array)[10]) {
/* ... */
... index[*array] ...
/* or */
... (*array)[index] ...
return;
}
 
K

Keith Thompson

Shao Miller said:
On 6/24/2011 17:09, jacob navia wrote:

[ Snipping everything }

What advantage does C++ reference have? None say I. Pass&var and accept
*var and all is solved simply. Tell me where I'm wrong.

For one, you don't have to test for NULL,

(By which you obviously mean a null pointer value. I don't use 'if (p
== NULL)' but 'if (!p)'.)

I prefer to be more explicit, but your mileage obviously varies.
But I still don't fully perceive this particular benefit, here.

For "static" and "automatic" objects, if you pass '&x', there can be
little doubt that the called function gets a valid "reference" to an
object. This can be observed at translation time.

For "allocated" objects, if we check for allocation success (not
everyone does, of course), then there should be no doubt about having a
valid object reference.

Sure, the *caller* should know whether a pointer value it's passing is,
or might be, or definitely isn't a null pointer. But the function
itself doesn't.

Sometimes a null pointer is a valid value. Sometimes it isn't.
Reference parameters (in languages that support them) are for the
latter case.

[...]
 

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
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top