Calling mechanisms and struct literals


J

James Harris

Some observations on C compiler calling mechanisms and structure
literals.

No need to reply. I am looking at inter-language working so this is
not necessarily about standard C but these are some notes of findings
while looking at ways gcc compiled specific constructs. Might be of
interest to some others. All errors below mine and not gcc's!

Target Routine
==============

The normal func(...) compiled, as expected, to the x86 assembly code

call func

The indirect (*func_p)(...) compiled to

call [func_p]

I.e. an indirect call where the address of func is stored in func_p.
Interestingly as long as func_p was declared as int (*func_p)(...)
even the bare call to func_p(...) (without the parens around the
function name in the call) compiled to the indirect

call [func_p]

So where an indirect call to a function was wanted the memory cell
holding the address of the function had to be declared as such. When
that cell was 'called' the compiler generated an indirect call to the
referent. That was a surprise, but a pleasant one. It means I only
need to declare a pointer as pointing to a function for that function
to be called through the pointer and I can stick with the familiar and
normal call syntax. Not sure if it is standard that C work this way.

Parameters
=========

Given

struct pblock_func {
int fd;
int mlen;
} pb1;

void (*func_p)(struct pblock_func *);

a call func_p(&pb1) compiled to

push pb1 ;i.e. the address of pb1
call [func_p]

In other words the parameter block is a structure in memory and the
stack holds a pointer to it. Even given this mechanism the stack can
hold both the parameter block and the address of it with

func_p(&(struct pblock_func){4, 11});

Being previously unaware of struct literals the ability to code this
was another surprise! Again, a good surprise, though it looks a bit
odd.

One More
========

I found that later unspecified elements of the anonymous parameter
block were implicitly zeroed so in

struct x {
int arg;
int result;
};

func_p(&(struct x){6});

Only the arg was specified (not the result) but gcc zeroed the missing
component of the anonymous struct.

James
 
Ad

Advertisements

B

Ben Bacarisse

James Harris said:
Some observations on C compiler calling mechanisms and structure
literals.

No need to reply. I am looking at inter-language working so this is
not necessarily about standard C but these are some notes of findings
while looking at ways gcc compiled specific constructs. Might be of
interest to some others. All errors below mine and not gcc's!

Target Routine
==============

The normal func(...) compiled, as expected, to the x86 assembly code

call func

The indirect (*func_p)(...) compiled to

call [func_p]

I.e. an indirect call where the address of func is stored in func_p.
Interestingly as long as func_p was declared as int (*func_p)(...)
even the bare call to func_p(...) (without the parens around the
function name in the call) compiled to the indirect

call [func_p]

So where an indirect call to a function was wanted the memory cell
holding the address of the function had to be declared as such. When
that cell was 'called' the compiler generated an indirect call to the
referent. That was a surprise, but a pleasant one. It means I only
need to declare a pointer as pointing to a function for that function
to be called through the pointer and I can stick with the familiar and
normal call syntax. Not sure if it is standard that C work this way.

Yes, it is. From the standard's point of view, a function is always
called though a pointer. When you write func(...), the function
designator is converted to a pointer type, in an analogous way to the
array to pointer conversion in an expression like array[42]. So, from
point of view of C's abstract evaluation, a call like (*func_p)(...)
involves a dereference yielding a function, which is then converted
back to a pointer so the call can happen! In effect, the old syntax,
where you *had* to write (*func_p)(...), has become the "special case".
Parameters
=========

Given

struct pblock_func {
int fd;
int mlen;
} pb1;

void (*func_p)(struct pblock_func *);

a call func_p(&pb1) compiled to

push pb1 ;i.e. the address of pb1
call [func_p]

In other words the parameter block is a structure in memory and the
stack holds a pointer to it. Even given this mechanism the stack can
hold both the parameter block and the address of it with

func_p(&(struct pblock_func){4, 11});

Being previously unaware of struct literals the ability to code this
was another surprise! Again, a good surprise, though it looks a bit
odd.

The C99 standard calls them compound literals (and they have not been
made optional in C11!).
One More
========

I found that later unspecified elements of the anonymous parameter
block were implicitly zeroed so in

struct x {
int arg;
int result;
};

func_p(&(struct x){6});

Only the arg was specified (not the result) but gcc zeroed the missing
component of the anonymous struct.

Again, as per the language definition. Only when no members are
initialised can the struct be left un-zeroed.

The syntax does not let you do that with a compound literal -- there
must always be at least one initialised member -- but this is not a
problem (as far as I can see) because, due it its lifetime, there is no
sensible use for an uninitialised compound literal.
 

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

Top