inline function or macro?

J

jacob navia

One situation where macros are the only solution, and inline functions
just do not cut it is when you have several structures that share a
common field, and you want to access it without a function call.

For instance in a container library (strange, what a coincidence :) )
all the containers share the "count" field, that access the number of
elements in the container.

Here it would be impossible to use an inline function since all the
containers are different types. A macro is the only solution:

#define GetCount(container) (container->count)

This will work with all containers. Unless you use lcc-win and have
true generic functions (or use C++) the macro is the only really
portable solution.
 
N

Nick

jacob navia said:
One situation where macros are the only solution, and inline functions
just do not cut it is when you have several structures that share a
common field, and you want to access it without a function call.

For instance in a container library (strange, what a coincidence :) )
all the containers share the "count" field, that access the number of
elements in the container.

Here it would be impossible to use an inline function since all the
containers are different types. A macro is the only solution:

#define GetCount(container) (container->count)

This will work with all containers. Unless you use lcc-win and have
true generic functions (or use C++) the macro is the only really
portable solution.

Although I've done this myself (even when not needing to work on generic
structures; for example my dynamic strings have dstr(x) to get the
c-string from x and dstrlen(x) to get the length; each of these is just
a macro to hide access to a member of the structure), at the back of my
mind I'm not entirely convinced by it.

After all, container->count is every bit as readable as
GetCount(container) and it's actually more like the syntax in other
popular languages (where it could be container.count). The benefit of
using a (probably not inline) function to get the field is that you can
then hide the structure away inside the library and not expose it to the
user. With the macro you're exposing everything, you're just not
documenting it. So why not just document only the fields the user is
allowed to change, and let them do it using standard syntax.

After all, there's nothing the macro does to prevent the user from doing
GetCount(container) = 18;
 
F

Francois Grieu

Nick wrote :
Although I've done this myself (even when not needing to work on generic
structures; for example my dynamic strings have dstr(x) to get the
c-string from x and dstrlen(x) to get the length; each of these is just
a macro to hide access to a member of the structure), at the back of my
mind I'm not entirely convinced by it.

After all, container->count is every bit as readable as
GetCount(container) and it's actually more like the syntax in other
popular languages (where it could be container.count). The benefit of
using a (probably not inline) function to get the field is that you can
then hide the structure away inside the library and not expose it to the
user. With the macro you're exposing everything, you're just not
documenting it. So why not just document only the fields the user is
allowed to change, and let them do it using standard syntax.

After all, there's nothing the macro does to prevent the user from doing
GetCount(container) = 18;

This could be solved by
#define GetCount(container) ((int)(container->count))

Francois Grieu
 
F

Francois Grieu

I wrote
#define GetCount(container) ((int)(container->count))

but now I'm leaning towards
#define GetCount(container) (1?0:container->count))
 
I

Ike Naar

I wrote
#define GetCount(container) ((int)(container->count))

but now I'm leaning towards
#define GetCount(container) (1?0:container->count))

Are you sure?
 
N

Nick

Francois Grieu said:
I wrote
#define GetCount(container) ((int)(container->count))

but now I'm leaning towards
#define GetCount(container) (1?0:container->count))

Apart from the syntax error of course!

How about
#define GetCount(container) (0+container->count)
assuming count is a number of some sort (it had better be!). Plus a
comment to explain why you are doing this.
 
F

Francois Grieu

Ike Naar a écrit :
Are you sure?

No. That's why I (tried to) cancel the post.
#define GetCount(container) (1?0:container->count)

Francois Grieu
 
E

Eric Sosman

One situation where macros are the only solution, and inline functions
just do not cut it is when you have several structures that share a
common field, and you want to access it without a function call.

For instance in a container library (strange, what a coincidence :) )
all the containers share the "count" field, that access the number of
elements in the container.

Here it would be impossible to use an inline function since all the
containers are different types. A macro is the only solution:

#define GetCount(container) (container->count)

This will work with all containers. Unless you use lcc-win and have
true generic functions (or use C++) the macro is the only really
portable solution.

"Only?"

typedef struct {
size_t count;
nobili_t baron;
royal_t duke;
} AllContainersHaveThis;

typedef struct {
AllContainersHaveThis common;
vani_t all_is;
} ContainerOne;

typedef struct {
AllContainersHaveThis common;
varie_t spice_of_life;
} ContainerTwo;

typedef struct {
AllContainersHaveThis common;
portabili_t too_heavy_to_carry;
} ContainerThree;

Or you can "turn it inside out:"

typedef struct {
vani_t all_is;
} OneSpecial;

typedef struct {
varie_t spice_of_life;
} TwoSpecial;

typedef struct {
portabili_t too_heavy_to_carry;
} ThreeSpecial;

typedef struct {
size_t count;
nobili_t baron;
royal_t duke;
union {
OneSpecial one;
TwoSpecial two;
ThreeSpecial three;
} specialization;
} Container;
 
I

Ike Naar

Ike Naar a écrit :

No. That's why I (tried to) cancel the post.
#define GetCount(container) (1?0:container->count)

It still seems wrong. I think you mean
#define GetCount(container) (0 ? 0 : (container)->count)
 
J

jacob navia

Eric Sosman a écrit :
typedef struct {
size_t count;
nobili_t baron;
royal_t duke;
} AllContainersHaveThis;

typedef struct {
AllContainersHaveThis common;
vani_t all_is;
} ContainerOne;

typedef struct {
AllContainersHaveThis common;
varie_t spice_of_life;
} ContainerTwo;

typedef struct {
AllContainersHaveThis common;
portabili_t too_heavy_to_carry;
} ContainerThree;

Sure, but then the access is
container->common.count;
and not
container->count;
what is easier on the user.
Or you can "turn it inside out:"

typedef struct {
vani_t all_is;
} OneSpecial;

typedef struct {
varie_t spice_of_life;
} TwoSpecial;

typedef struct {
portabili_t too_heavy_to_carry;
} ThreeSpecial;

typedef struct {
size_t count;
nobili_t baron;
royal_t duke;
union {
OneSpecial one;
TwoSpecial two;
ThreeSpecial three;
} specialization;
} Container;

True, that is possible too, but then the access to the vtable
is even longer. Instead of
container->lpVtble->Add(container,"foo");
you would have
container->one->lpVtbl->Add(container,"Foo");

It is already difficult to have to type the first form, an even
more verbose access would be really bad...


Another thing would be to use the preprocessor

typedef strucy newContainer {
#include "commonfields.h"
int extrafield;
int *data;
};

But this doesn't really help a lot.
 
S

spinoza1111

One situation where macros are the only solution, and inline functions
just do not cut it is when you have several structures that share a
common field, and you want to access it without a function call.

For instance in a container library (strange, what a coincidence :) )
all the containers share the "count" field, that access the number of
elements in the container.

Here it would be impossible to use an inline function since all the
containers are different types. A macro is the only solution:

#define GetCount(container) (container->count)

This will work with all containers. Unless you use lcc-win and have
true generic functions (or use C++) the macro is the only really
portable solution.

Yes, but that is why generics were added to .Net.

public static class containerTools<containerType>
{
public static int getCount(containerType container)
{
return container.count;
}
}

Simple, right?

There is a problem in your code. If container is an expression, the ->
may associate incorrectly. A well known fix that you probably know
would be to code

#define GetCount(container) ((container)->count)

unless I'm missing something.

Also, if container doesn't have a count, the emitted code won't
compile. I understand that this is true for macros in general. Either
the macro is well-documented, or you can see its code as in a white or
transparent box.

Lacking Turing-complete conditional assembly and a richer set of
functions which have long been available in languages such as
assembler, the macro is not able to validate its own parameters,
whereas I was able to do this in the macro language of IBM BAL. Even
if a C preprocessor could detect many errors, it has no way of
informing the user save a crude hack such as generating a printf()
that waits until runtime to say "you made an error"!

Now, a colleague whose name I won't mention in a probably futile
effort to make sure he stays away thinks that "macro processing" and
"conditional compilation" are two separate things: but in fact, when
you finish mere textual substitution, you're not done, since you
cannot error check parameters. This in fact was why almost as soon as
simple textual macros appeared in IBM assemblers of the 1950s, they
had to be enhanced with conditional compilation, the ability to emit
diagnostics and even crude loops that used macro-expansion-time Go Tos
to create loops. They were Turing-complete.

Have you considered, Mr Navia, replacing the C preprocessor with such
a macro processor, since you appear to be in the (too me rather
*maudit*) business of trying to make a sensible language out of C?

But: note that far more work is needed in C to get to the purse of
silk from the ear of sow or tongue of bat or eye of newt stage that it
appears to me C is stuck in.
 
E

Eric Sosman

Eric Sosman a écrit :
typedef struct {
size_t count;
nobili_t baron;
royal_t duke;
} AllContainersHaveThis;
[...]

Sure, but then the access is
container->common.count;
and not
container->count;
what is easier on the user.

If you can do `container->count', why bother with
your `GetCount(container)' macro in the first place?
What problem are you trying to solve?
 
J

jacob navia

Eric Sosman a écrit :
Eric Sosman a écrit :
typedef struct {
size_t count;
nobili_t baron;
royal_t duke;
} AllContainersHaveThis;
[...]

Sure, but then the access is
container->common.count;
and not
container->count;
what is easier on the user.

If you can do `container->count', why bother with
your `GetCount(container)' macro in the first place?
What problem are you trying to solve?

I would prefer not to let users use "->count" directly in case
I need to change it later, because, for instance, capitalization
problems, (Count or count?), or because it is better to call
it NumberOfEelemnts, etc.

But not ALL members of the common subset have macros for them
since I want to avoid using common names as much as possible.

The GetCount macro is on by default, but if it collides with
one name in your name space you should be able to disable it.

As you know, C has no "hidden/protected" structure members.
 
E

Eric Sosman

Eric Sosman a écrit :
Eric Sosman a écrit :

typedef struct {
size_t count;
nobili_t baron;
royal_t duke;
} AllContainersHaveThis;
[...]

Sure, but then the access is
container->common.count;
and not
container->count;
what is easier on the user.

If you can do `container->count', why bother with
your `GetCount(container)' macro in the first place?
What problem are you trying to solve?

I would prefer not to let users use "->count" directly in case
I need to change it later, because, for instance, capitalization
problems, (Count or count?), or because it is better to call
it NumberOfEelemnts, etc.

If the users aren't supposed to access `count' directly,
why object that `container->count' is "easier on the user" than
`container->common.count'? Neither form will be used at all,
so why prefer one as "easier" than the other?

I still don't get it ...
But not ALL members of the common subset have macros for them
since I want to avoid using common names as much as possible.

Sorry: I don't understand this at all. I imagine this is
because I lack a good deal of context, design and implementation
details that reside in your head but not in mine.
The GetCount macro is on by default, but if it collides with
one name in your name space you should be able to disable it.

And thus give up the ability to find out how many elements
a container holds? I still *really* don't get it ...
As you know, C has no "hidden/protected" structure members.

No. It's all or nothing: Expose all of a struct's elements,
or make the whole struct an incomplete type and hide everything.
(For an abstract data type like "container," the latter seems
such a natural choice that I don't understand why you avoid it.)
 
K

Keith Thompson

jacob navia said:
One situation where macros are the only solution, and inline functions
just do not cut it is when you have several structures that share a
common field, and you want to access it without a function call.

For instance in a container library (strange, what a coincidence :) )
all the containers share the "count" field, that access the number of
elements in the container.

Here it would be impossible to use an inline function since all the
containers are different types. A macro is the only solution:

#define GetCount(container) (container->count)

This will work with all containers. Unless you use lcc-win and have
true generic functions (or use C++) the macro is the only really
portable solution.

Judicious use of void* can let you use functions (inline or not),
though at some loss of type checking. The following sample code,
which expands on what Eric Sosman pointed, is a bit long; the GetCount
function is the relevant part.

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

typedef struct {
size_t count;
} AllContainersHaveThis;

typedef struct {
AllContainersHaveThis common;
int One;
} ContainerOne;

typedef struct {
AllContainersHaveThis common;
char *Two;
} ContainerTwo;

typedef struct {
AllContainersHaveThis common;
double Three;
} ContainerThree;

ContainerOne *new1(size_t count, int One)
{
ContainerOne *const result = malloc(sizeof *result);
if (result != NULL) {
result->common.count = count;
result->One = One;
}
return result;
}

ContainerTwo *new2(size_t count, char *Two)
{
ContainerTwo *const result = malloc(sizeof *result);
if (result != NULL) {
result->common.count = count;
result->Two = Two;
}
return result;
}

ContainerThree *new3(size_t count, double Three)
{
ContainerThree *const result = malloc(sizeof *result);
if (result != NULL) {
result->common.count = count;
result->Three = Three;
}
return result;
}

size_t GetCount(void *container)
{
const AllContainersHaveThis *common_ptr = container;
return common_ptr->count;
}

int main(void)
{
ContainerOne *c1 = new1(10, 42);
ContainerTwo *c2 = new2(20, "hello");
ContainerThree *c3 = new3(30, 1.375);
printf("GetCount(c1) = %zu\n", GetCount(c1));
printf("GetCount(c2) = %zu\n", GetCount(c2));
printf("GetCount(c3) = %zu\n", GetCount(c3));
return 0;
}
 
K

Keith Thompson

Keith Thompson said:
jacob navia said:
One situation where macros are the only solution, and inline functions
just do not cut it is when you have several structures that share a
common field, and you want to access it without a function call.

For instance in a container library (strange, what a coincidence :) )
all the containers share the "count" field, that access the number of
elements in the container.

Here it would be impossible to use an inline function since all the
containers are different types. A macro is the only solution:

#define GetCount(container) (container->count)

This will work with all containers. Unless you use lcc-win and have
true generic functions (or use C++) the macro is the only really
portable solution.

Judicious use of void* can let you use functions (inline or not),
though at some loss of type checking. The following sample code,
which expands on what Eric Sosman pointed, is a bit long; the GetCount
function is the relevant part. [snip]
size_t GetCount(void *container)
{
const AllContainersHaveThis *common_ptr = container;
return common_ptr->count;
}
[snip]

A major drawback of this approach is that the compiler won't
complain about a call like
GetCount("hello");
(On my system it returned 1819043176, which is meaningful but not
in any useful way.)
 
F

Flash Gordon

Eric said:
Eric Sosman a écrit :
On 1/2/2010 12:39 PM, jacob navia wrote:
Eric Sosman a écrit :

typedef struct {
size_t count;
nobili_t baron;
royal_t duke;
} AllContainersHaveThis;
[...]

Sure, but then the access is
container->common.count;
and not
container->count;
what is easier on the user.

If you can do `container->count', why bother with
your `GetCount(container)' macro in the first place?
What problem are you trying to solve?

I would prefer not to let users use "->count" directly in case
I need to change it later, because, for instance, capitalization
problems, (Count or count?), or because it is better to call
it NumberOfEelemnts, etc.

If you might decide to change it's name, then might you not also decide
to change GetCount to GetNumberOfElements? Or change its capitalization?
The only solution to the problem of what to call things and possibly
needing to rename them is to design everything sufficiently that the
odds are the name will always be appropriate and not clash with anything
else you might want to do.
If the users aren't supposed to access `count' directly,
why object that `container->count' is "easier on the user" than
`container->common.count'? Neither form will be used at all,
so why prefer one as "easier" than the other?

I still don't get it ...


Sorry: I don't understand this at all. I imagine this is
because I lack a good deal of context, design and implementation
details that reside in your head but not in mine.

It does seem odd to me. The one reason I can see you might want to do
some things wrapped in a macro or inline function is if count *might* be
a simple field or you *might* be calling a function which actually
counts the elements, but in that case make it a function with the simple
case just being a simple inline function.
And thus give up the ability to find out how many elements
a container holds? I still *really* don't get it ...

Well, you could still access container->count ... ;-)
The macros/functions should have an appropriate prefix to minimise the
chances of a name clash. E.g. start everything with cnt (or Cnt) or
whatever. After all, you might be using another library which has a
GetCount function (which is, I think, Jacob's concern here).
No. It's all or nothing: Expose all of a struct's elements,
or make the whole struct an incomplete type and hide everything.
(For an abstract data type like "container," the latter seems
such a natural choice that I don't understand why you avoid it.)

It would be nice if you could have a struct which contains an incomplete
struct. Which, of course, would make it incomplete but still allow
access to some things...

struct container {
size_t count;
struct hidden hidden;
}

If this was added to C the container struct would obviously have most of
the same restrictions as any other incomplete type, i.e. you could
declare pointers to the type, not arrays or objects. You would need a
special case rule that you could dereference it if and *only* if you
then just accessed a member the definition of which you could see. Also
the incomplete type would have to be at the end (just as with flexible
array members).

I suppose you could just do an array which was large enough for all the
extra info you wanted then cast to/from the correct
pointer-to-struct-type inside the library.
 

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

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top