Defining an alias

J

jacob navia

Sometimes you need to have two functions that have the same body.

For instance, in my container library I have a function
"Add" that will add an element at the end of the list,
and another "Pop" that will take out the first element of the list.

If you implement a queue as a list, the function "Enqueue" will be
the same as "Add", and "Dequeue" the same as "Pop". The only
way to do this in standardese is:

int Enqueue(List *l, void *item)
{
return Add(l,item);
}

This is wasteful since the call overhead is payed for
no reason.

The syntax for doing that under lcc-win is:

int __declspec(naked) SomeNewName(int a, int b) { }
int SomeOtherName(int a,int b)
{
// Here we have the real body of the function
}

The first declaration specifies a "naked" function i.e. one which
the compiler will treat as special and not generate any prologue
nor epilogue to it, and will not complain about missing return
values.

The second declaration is the body of the function. The first one
will be just an assembler label. It wilk take zero bytes of space.

"Naked" functions are supposed to be assembly language ones, by the way.

All this syntax is quite horrible. I am conforted however, because gcc
has an even uglier syntax:

http://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/Function-Attributes.html:

The alias attribute causes the declaration to be emitted as an alias for another symbol, which must
be specified. For instance,

void __f () { /* Do something. */; }
void f () __attribute__ ((weak, alias ("__f")));


defines `f' to be a weak alias for `__f'. It is an error if `__f' is not defined in the same
translation unit.

It is not clear what "weak" means in this context, and I am not sure that
gcc does the same thing as lcc-win...

Any ideas? Which syntax would be better?

Thanks
 
A

Alan Curry

Sometimes you need to have two functions that have the same body.

For instance, in my container library I have a function
"Add" that will add an element at the end of the list,
and another "Pop" that will take out the first element of the list.

If you implement a queue as a list, the function "Enqueue" will be
the same as "Add", and "Dequeue" the same as "Pop". The only
way to do this in standardese is:

int Enqueue(List *l, void *item)
{
return Add(l,item);
}

This is wasteful since the call overhead is payed for
no reason.

Some people would just make it static inline in the header file, then there's
no overhead (if the compiler does inlines at all).
The syntax for doing that under lcc-win is:

int __declspec(naked) SomeNewName(int a, int b) { }
int SomeOtherName(int a,int b)
{
// Here we have the real body of the function
}

I see nothing that actually specifies where SomeNewName's "real body" is to
be found. Does it just take the next one in the source file? Adjacency in the
source code seems like a flimsy thing to rely on.
http://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/Function-Attributes.html:

The alias attribute causes the declaration to be emitted as an alias for
another symbol, which must
be specified. For instance,

void __f () { /* Do something. */; }
void f () __attribute__ ((weak, alias ("__f")));


defines `f' to be a weak alias for `__f'. It is an error if `__f' is not
defined in the same
translation unit.

weak symbols are used in libraries (libc especially) to provide a function
that is available in the user's namespace, but will get out of the way if he
provides his own definition. So you can call a non-stdc function like fork()
and the linker will find the one in libc, or you can have your own global
variable called fork in a plain C program and the linker won't complain about
the conflict, since the one in libc is weak.

The double-underscore version of the function is there because the
implementation of standard C functions needs to call the non-stdc functions
sometimes. system() must call fork(), so it uses __fork() to avoid a conflict
in a program that makes use of system() but also has an unrelated global
variable or function named "fork". fopen() must call open(), so it calls
__open() which is a weak alias for open(), etc.
It is not clear what "weak" means in this context, and I am not sure that
gcc does the same thing as lcc-win...

The gcc syntax actually tells you that the 2 names are related, by having the
alias "__f" attribute attached to the declaration of f. They don't need to be
one right after the other in a specific order, like your "naked" thing does.
 
S

Seebs

It is not clear what "weak" means in this context, and I am not sure that
gcc does the same thing as lcc-win...

"weak" is a traditional thing in linkers at least on the recent unixy systems
I've used. A weak reference is a reference which exists if needed but not
found, but which never clashes with anything.

So, as an example: Some BSDish systems used to declare a symbol "end" which
referred to the end of the program's space, roughly. That could be a problem
if you defined a symbol named "end" and tried to call it or use it. So!
Solution is, make it a weak reference. If you refer to end and link without
providing anything named end, you pick that one up. If you provide your own,
yours wins.

This is often used to handle things where a given function name is in the
user's namespace but is traditional. For instance, in standard C, the user
is permitted to define a function named "open". In unix-land, open is a
standard system call, which is usually (but not always) accessed through a
C wrapper. The gcc approach would be that the library would provide a
symbol named something like __open or __syscall_open, and then a "weak
alias" under the name open.
Any ideas? Which syntax would be better?

The gcc syntax is more flexible, because it can be used to refer to things
that aren't defined anywhere near you. You can have many references to a
single thing, and the "weak" reference allows you to ensure that you are
more resilient in the face of possible namespace clashes.

-s
 
I

Ian Collins

jacob said:
Sometimes you need to have two functions that have the same body.

For instance, in my container library I have a function
"Add" that will add an element at the end of the list,
and another "Pop" that will take out the first element of the list.

If you implement a queue as a list, the function "Enqueue" will be
the same as "Add", and "Dequeue" the same as "Pop". The only
way to do this in standardese is:

int Enqueue(List *l, void *item)
{
return Add(l,item);
}

This is wasteful since the call overhead is payed for
no reason.

But surely most, if not all, compiler will inline such a trivial function?

All this syntax is quite horrible. I am conforted however, because gcc
has an even uglier syntax:

http://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/Function-Attributes.html:

The alias attribute causes the declaration to be emitted as an alias for
another symbol, which must be specified. For instance,

void __f () { /* Do something. */; }
void f () __attribute__ ((weak, alias ("__f")));


defines `f' to be a weak alias for `__f'. It is an error if `__f' is not
defined in the same
translation unit.

It is not clear what "weak" means in this context, and I am not sure that
gcc does the same thing as lcc-win...

The usual meaning (at least in Unix land) is described here:
http://en.wikipedia.org/wiki/Weak_symbol

The example above appears to be an extension of the weak symbol concept.
Any ideas? Which syntax would be better?

Let the compiler inline the call.
 
S

Stefan Ram

jacob navia said:
the same as "Add", and "Dequeue" the same as "Pop". The only
way to do this in standardese is:
int Enqueue(List *l, void *item)
{
return Add(l,item);
}

Why not

int (*Enqueue)(List *l, void *item) = Add;

?
 
B

Beej Jorgensen

But surely most, if not all, compiler will inline such a trivial function?
Let the compiler inline the call.

Seconded. If that wasn't working, I'd probably use the function pointer
solution.

-Beej
 
J

jacob navia

jacob navia a écrit :


(snip)

Thanks for the answers guys. Yes, the "static inline" syntax is better.

I think that the container library will require C99 then, and leave
Microsoft compilers out... They have inline, but I do not remember if
they accept it in C mode.

jacob
 
K

Keith Thompson

jacob navia said:
jacob navia a écrit :
(snip)

Thanks for the answers guys. Yes, the "static inline" syntax is better.

I think that the container library will require C99 then, and leave
Microsoft compilers out... They have inline, but I do not remember if
they accept it in C mode.

What's wrong with the const function pointer solution?
 
H

Hallvard B Furuseth

Ian said:
But surely most, if not all, compiler will inline such a trivial
function?

gcc doesn't by default, even if it is declared inline.

Only gcc -O (optimizing) inlines functions declared 'inline',
and also other small functions called just once. At level -O3
it'll inline small functions called more than once.
 
I

Ian Collins

Hallvard said:
gcc doesn't by default, even if it is declared inline.

Only gcc -O (optimizing) inlines functions declared 'inline',
and also other small functions called just once. At level -O3
it'll inline small functions called more than once.

How often do you deploy application built without any optimisation?
 
A

Antoninus Twink

I think that the container library will require C99 then, and leave
Microsoft compilers out...

You'll also excluded Heathfield's version of gcc from the last century!
 
S

Stefan Ram

int (*const Enqueue)(List *l, void *item) = Add;

gcc seems to be willing to replace the call to »enqueue«
with a call to »add« when it is compiling »main«:

#include <stdlib.h>
inline int add( void ){ return 7; }
int( * const enqueue )( void )= add;
int main( void ){ exit( enqueue() ); }

gcc -O3 -S -std=c99 -finline-functions-called-once test.c

main:
...
call add
movl %eax, (%esp)
call exit
...

So it acknowledges that »enqueue« will always be »add«.
While without the »const«, it will call »enqueue«.

main:
...
call *enqueue
movl %eax, (%esp)
call exit
...

Thus, there is no reason visible that forbids gcc to inline
the call in the first case - it just does not do it,
but then this is a property of a special implementation,
not necessarily of all implementations of the programming
language C.
 
B

Ben Bacarisse

gcc seems to be willing to replace the call to »enqueue«
with a call to »add« when it is compiling »main«:

#include <stdlib.h>
inline int add( void ){ return 7; }
int( * const enqueue )( void )= add;
int main( void ){ exit( enqueue() ); }
So it acknowledges that »enqueue« will always be »add«.
While without the »const«, it will call »enqueue«.
Thus, there is no reason visible that forbids gcc to inline
the call in the first case - it just does not do it,

My gcc does. It seems there is no reason not to use this alias method
is the compiler can even inline the pointed-to function.

<snip>
 
F

Fred

My gcc does.  It seems there is no reason not to use this alias method
is the compiler can even inline the pointed-to function.

- Show quoted text -

I don't get it. If the two functions are truly identical, why not do
this
(this thread has been inconsistent in capitalization of the function
names):

#define Enqueue Add
 
B

bartc

Stefan said:
Why not

int (*Enqueue)(List *l, void *item) = Add;

Or:

int Enqueue(List *l, void *item) = Add;

(which of course is a new syntax, but does away with the extra obfuscating
indirection layer.)

Or I might just use (and I don't care myself about new keywords):

alias Enqueue = Add;

which saves repeating (and having to maintain) the function signature.

(I quite like Fred's macro solution too, if there's no catch.)

All these methods however suggest some hierarchy between Enqueue and Add,
whereas they should be both be at the same level. Perhaps then define both
in terms of a dummy third routine:

int Enqueue_or_Add(List *l, void *item) {...}

alias Enqueue = Enqueue_or_Add;
alias Add = Enqueue_or_Add;
 
B

Ben Bacarisse

I don't get it. If the two functions are truly identical, why not do
this
(this thread has been inconsistent in capitalization of the function
names):

#define Enqueue Add

A lot of people have grown wary of macro-based solutions simply
because the mechanism is so crude. Using the above will be fine in
the vast majority of cases but you'll be tripped up if you try to use
a macro to replace Enqueue with my_debug_Enqueue and you might be
puzzled that the debugger shows that you no longer have a struct
Enqueue (badly named, I agree, but that is not really the point).
 
H

Hallvard B Furuseth

Ian said:
How often do you deploy application built without any optimisation?

Don't know, I don't compile most of the programs I run. I do hear from
people who say they don't use gcc's optimization because it is broken.
(My guess is their application is broken, but what do I know...)

In any case, gcc -O2 is a common optimization level - and like I just
said, that's not enough if the function was not declared inline.
 
H

Hallvard B Furuseth

Gareth said:
But if you're not compiling with any optimization, you don't care about
the performance hit of the extra function setup, so its a moot point.

I do in fact care about producing reasonable default behavior, so I try
to avoid active pessimizations. Though in this case and optimzation is
likely not the main point, code bloat is. (Lots of compiled small
unused functions which could have been removed.)
 

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,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top