[openbeos] Re: Pointer or reference?

  • From: Ingo Weinhold <bonefish@xxxxxxxxxxxxxxx>
  • To: openbeos@xxxxxxxxxxxxx
  • Date: Tue, 30 Mar 2004 00:17:12 +0200

On 2004-03-29 at 02:02:32 [+0200], anqe wrote:
> 
> > I'm not sure, what you mean by `code time constant', but passing something
> > per reference means nothing else than that it is not passed by value. The
> > `const' concept has nothing to do with this; a reference can refer to both
> > constants and mutables.
> >
> > > Either way the 4B is still gonna be transferred somewhere along the
> line,
> > > via stack though the compiler nowadays might be passing it through in
> > > fastcall.
> > >
> > > That &string is gonna make the compiler generate an "lea esi, string"
> which
> > > could possibly be avoided by using a constant pointer to the string. My
> > > reasoning for this is that the compiler knows where it should be
> > > initializing the variable and in some cases can make the assumption as
> to
> > > where it is, allowing the lea to be avoided.
> > >
> > > I could be off the mark, if so just ignore me (I try my best to ignore
> me)
> > > but it seems that if worrying about 4B of memory is an issue then there
> are
> > > probably other places to look for speed first. Condition hoisting and
> > > appropriate usage of case and nested if structures would probably yield
> more
> > > performance than chassing all calls.
> >
> > Passing a reference to a function is not any different from passing a
> pointer
> > to it. In both cases the address of the referenced object must be passed.
> >
> > The following two functions, for instance, are compiled to exactly the
> same
> > executable code:
> >
> > extern "C"
> > void
> > add_one(int& var)
> > {
> > var++;
> > }
> >
> > extern "C"
> > void
> > add_one(int* var)
> > {
> > (*var)++;
> > }
> 
> Neither of those examples correspond to a code time constant. There is an
> inherent difference when your dealing with constant pointers and references.
> 
> When the compiler passes a reference its sending a variable through without
> being specific about what its going to be used for.
> 
> void echomsg (int& rString) {
>     if (rString != 0) {
>         printf(*rString);
>     }
>     else {
>         printf("Echod null string");
>     }
> }

Sorry, but this example is badly broken. Neither can you dereference an 
`int&' not would printf() eat it.

> and say you called it as
> 
> // Some stuff now echo it to console
> echomsg(*ErrorMessage);
> // Where error message is a string defined when the code is written (hence
> code constant)
> 
> that will make the compiler generate something along the lines of
> 
> // <- Somestuff
> lea    eax, ErrorMessage
> push eax
> call    echomsg
> -->
>     enter    0,4    //I don't normally use enter so that might be a missuse
>     pop    eax
>     test    eax,eax
>     jz        $steptoerror
>     ...
>     ...
> 
> and so on

I wouldn't claim to speak x86 assembly, so I don't try to comment that.

> Because your message has been defined at code time its not going to change
> when the program runs, so this allows the compiler to make assumptions about
> the data that it can't if you give it a reference.
> 
> void echomsg (const char* rString) {
>        printf(rString);
> }
> 
> will allow the lea to be eliminated and the compiled code can become
> 
> // <- Somestuff
> push [ErrorMessage]        // !!! Different
> call    echomsg                    // !!! Different
> -->
>     enter    0,4    //I don't normally use enter so that might be a missuse
>     pop    eax
> 
> 
> thats one instruction removed from the call and the push is now an rmw
> instruction so it should pipeline better in the cpu.

Again, I don't know enough about x86 assembler to argue about into what the 
compiler produces exactly, but I'm sure enough to know that there is simply 
no difference between passing a pointer and passing a reference.

I think, I know now, what you mean by `code time constant'. I suppose that 
refers to constants that can be evaluated at compile time. Again, there is no 
difference in passing pointers and references to those. Example:

const int c = 7;

extern "C"
int
add(int x, const int& y)
{
        return x + y;
}

void
test()
{
        int x = 1;
        x = add(x, c);
}

vs.

const int c = 7;

extern "C"
int
add(int x, const int* y)
{
        return x + *y;
}

void
test()
{
        int x = 1;
        x = add(x, &c);
}

Again the compiler produces exactly the same code.

> The other difference is
> that the cleanup for a null pointer can be removed because the compiler
> takes responisbility. Which isn't something it could do using reference, it
> had to trust the programmer to never type echomsg(NULL) without pointer
> cleanup. Whereas passing a NULL into the const char* version will most
> likely cause the compiler to at least give a warning.

No, it will not. Passing NULL for a const char* is completely legal. Nor does 
the compiler do any checking for NULL pointer or references in any other case.

> If the compiler were to inline the code then it could be simplified further.
> Then again my example is hardly realistic since calling a function to simply
> call printf is pretty much pointless.

In the above example, replace `extern "C"' by `static inline' and compile 
with -O1 and you'll see that the compiler produces exactly the same code 
again.

CU, Ingo

Other related posts: