Standard library macros

S

sandeep

Hi

We know that for historical reasons, many utilities provided by the
standard library *must* be implemented as macros instead of functions, ie
assert, the va_arg commands, offsetof, getchar... This was to remove the
function call overhead which was a significant inefficiency on the slow
processors around in the early days of C.

We also know that these efficiency concerns no longer matter so much, and
also the ISO Standard itself has recognised that macros are undesirable,
by introducing a better alternative (inline functions).

I would therefore propose that in the next ISO Standard, all standard
library commands are required to be implemented as functions, possibly
inline, and not as macros. This will lead to better type safety and avoid
problems with multiple evaluation side effects.
 
I

Ian Collins

Hi

We know that for historical reasons, many utilities provided by the
standard library *must* be implemented as macros instead of functions, ie
assert, the va_arg commands, offsetof, getchar... This was to remove the
function call overhead which was a significant inefficiency on the slow
processors around in the early days of C.

getchar() is defined as a function in the standard.
We also know that these efficiency concerns no longer matter so much, and
also the ISO Standard itself has recognised that macros are undesirable,
by introducing a better alternative (inline functions).

I would therefore propose that in the next ISO Standard, all standard
library commands are required to be implemented as functions, possibly
inline, and not as macros. This will lead to better type safety and avoid
problems with multiple evaluation side effects.

How would you implement assert as a function?

How would you implement an operator that takes a type as parameter, such
as offsetof() as a function?
 
E

Eric Sosman

Hi

We know that for historical reasons, many utilities provided by the
standard library *must* be implemented as macros instead of functions, ie
assert, the va_arg commands, offsetof, getchar... This was to remove the
function call overhead which was a significant inefficiency on the slow
processors around in the early days of C.

We also know that these efficiency concerns no longer matter so much, and
also the ISO Standard itself has recognised that macros are undesirable,
by introducing a better alternative (inline functions).

I would therefore propose that in the next ISO Standard, all standard
library commands are required to be implemented as functions, possibly
inline, and not as macros. This will lead to better type safety and avoid
problems with multiple evaluation side effects.

Show us your implementations of offsetof(), setjmp(), and
assert() as functions, and *then* we'll talk.
 
K

Keith Thompson

sandeep said:
We know that for historical reasons, many utilities provided by the
standard library *must* be implemented as macros instead of functions, ie
assert, the va_arg commands, offsetof, getchar... This was to remove the
function call overhead which was a significant inefficiency on the slow
processors around in the early days of C.

We also know that these efficiency concerns no longer matter so much, and
also the ISO Standard itself has recognised that macros are undesirable,
by introducing a better alternative (inline functions).

I would therefore propose that in the next ISO Standard, all standard
library commands are required to be implemented as functions, possibly
inline, and not as macros. This will lead to better type safety and avoid
problems with multiple evaluation side effects.

I don't believe anything in the standard library is required to be
a macro for efficiency reasons.

assert(), va_arg(), va_copy(), va_end(), va_start(), and offsetof()
are defined as macros because it's not possible to define them
as functions, even inline functions. (If you think it's possible,
I encourage you to try it.)

The getc() function, like any standard library function,
may optionally be implemented as a macro. The standard gives
implementations special permission for such a macro to evaluate the
stream argument more than once. This is for efficiency reasons,
but implementations needn't take advantage of this permission;
they can implement getc() as a macro that evaluates its argument
only once, or just as a function.
 
S

sandeep

Keith said:
I don't believe anything in the standard library is required to be a
macro for efficiency reasons.

assert(), va_arg(), va_copy(), va_end(), va_start(), and offsetof() are
defined as macros because it's not possible to define them as functions,
even inline functions. (If you think it's possible, I encourage you to
try it.)

Sometimes I imagine that you and Mr Sosmanji just look for reasons to
oppose my suggestions...

Obviously the implementation can "work magic" and do anything by
functions.

But the true point is that if the problem is not being able to pass type
names to functions, but being able to pass them to macros, why not
improve the language to allow *all* functions (both implementation and
user functions) to accept type names as arguments? This would also be
very helpful for type-generic / template-based programming which is now
very difficult in C.
The getc() function, like any standard library function, may optionally
be implemented as a macro. The standard gives implementations special
permission for such a macro to evaluate the stream argument more than
once. This is for efficiency reasons, but implementations needn't take
advantage of this permission; they can implement getc() as a macro that
evaluates its argument only once, or just as a function.

But with an underlying function available, the user can make use of it
themself, eg by passing it as a callback to another function!
 
T

Tim Rentsch

sandeep said:
But the true point is that if the problem is not being able to pass type
names to functions, but being able to pass them to macros, why not
improve the language to allow *all* functions (both implementation and
user functions) to accept type names as arguments?

Fantastic idea. Be sure to let everyone know when
you have something working.
 
B

BartC

sandeep said:
Keith Thompson writes:

Sometimes I imagine that you and Mr Sosmanji just look for reasons to
oppose my suggestions...

Obviously the implementation can "work magic" and do anything by
functions.

But the true point is that if the problem is not being able to pass type
names to functions, but being able to pass them to macros, why not
improve the language to allow *all* functions (both implementation and
user functions) to accept type names as arguments?

You want to totally reinvent the language into something quite different,
just so some built-in macros can be functions instead? (And after that you
will presumably ask why statements cannot also be implemented as functions.)
This would also be
very helpful for type-generic / template-based programming which is now
very difficult in C.

I don't see how it would help. Any 'type arguments' you see in templates
aren't runtime values.
But with an underlying function available, the user can make use of it
themself, eg by passing it as a callback to another function!

With getc(), that is easy enough to arrange without turning the entire
language upside-down.
 
I

Ian Collins

Obviously the implementation can "work magic" and do anything by
functions.

But the true point is that if the problem is not being able to pass type
names to functions, but being able to pass them to macros, why not
improve the language to allow *all* functions (both implementation and
user functions) to accept type names as arguments? This would also be
very helpful for type-generic / template-based programming which is now
very difficult in C.

Types aren't "passed" to macros. Nothing is passed to a macro. A macro
is expanded at compile time, which is the time when type information
exists. Compilers manipulate types and code manipulates instances of
types. Yes you could bind type information to a variable, but consider
the cost of doing so.

Template based generic programming does not require run time type
information, the type information is available to and used by the
compiler in instantiate instances of objects and functions. In C++ you
can have fun with compile time type (normally known as template
meta-programming) based programming, but while powerful when it can be
applied, the technique has limited uses.

Scripting languages use embedded type information to implement generic
programming, but that comes at a significant cost, which isn't the C way.
 
E

Eric Sosman

[...]
Sometimes I imagine that you and Mr Sosmanji just look for reasons to
oppose my suggestions...

Can't speak for Keith, but in my opinion a suggestion without
evidence of preparatory thought is deserving of opposition.
Obviously the implementation can "work magic" and do anything by
functions.

If it's magical, it's not a "function" in any useful sense.
For example, you could posit a magical offsetof() function -- but
tell me, please, how you will declare a function pointer that
points to it and can invoke it?
But the true point is that if the problem is not being able to pass type
names to functions, but being able to pass them to macros, why not
improve the language to allow *all* functions (both implementation and
user functions) to accept type names as arguments? This would also be
very helpful for type-generic / template-based programming which is now
very difficult in C.

Okay, a sweeping and transformative change to the entire language,
making "type" a value that can be passed around like an "int", compared
to, maybe have arithmetic performed on it, ... Again, I strongly
suspect you have given no thought to what your suggestion entails.

... and you still haven't addressed assert(). Observe that a
failing assert() must output *program source code* -- do you propose
that the running C program should also be able to inspect (and maybe
manipulate!) its own source code? Okay, yet another sweeping and
transformative change; C is now an interpreted language ...

... and you still haven't addressed va_start() and friends. No,
sandeepjijiji, you haven't even *begun* to think.
But with an underlying function available, the user can make use of it
themself, eg by passing it as a callback to another function!

Already possible, because getc() *is* a function. Not only have
you not thought, you have not read.
 
K

Keith Thompson

sandeep said:
Sometimes I imagine that you and Mr Sosmanji just look for reasons to
oppose my suggestions...

Not really. In this case, I merely pointed out that your suggestion is
based on incorrect assumptions and cannot be implemented in standard C
as it exists now. The only reason I disagreed with you is that you
were wrong.
Obviously the implementation can "work magic" and do anything by
functions.

But the true point is that if the problem is not being able to pass type
names to functions, but being able to pass them to macros, why not
improve the language to allow *all* functions (both implementation and
user functions) to accept type names as arguments? This would also be
very helpful for type-generic / template-based programming which is now
very difficult in C.

Your original point was something quite different, that some things
in the standard library are defined as macros "to remove the function
call overhead". That is untrue; they're defined as macros because
they cannot be defined as functions in standard C.

And now you're introducing an entirely new point that you didn't
mention, or even hint at, in your original post.
But with an underlying function available, the user can make use of it
themself, eg by passing it as a callback to another function!

Certainly. The standard requires the underlying function to
be available, as it does for all standard functions. The only
special thing about getc is that *if* it's implemented as a macro
(in addition to the required implementation as a function), that
macro is permitted to evaluate its stream argument more than once.
You can still pass the address of the getc function to another
function for use as a callback.

The vast majority of entities in the standard library that can
be invoked using syntax that looks like a function call *must*
be implemented as functions, and in addition *may* be implemented
as macros (which can be bypassed to get to the actual function).

Just one such entity, getc(), comes with permission for the macro
to evaluate its argument more than once. This provides significant
performance benefits, though I suspect an inline function could
provide similar benefits. You might have a valid point that the
special permission for getc() is obsolete, but I haven't thought
about it in any detail.

offsetof() takes a type name as its first argument, and a member
name as its second argument. In C as it's currently defined, it's
simply not possible for it to be defined as a function. (It's not
even possible to define it as a macro in portable C, which is part
of why it's in the standard library; implementations can implement
as a macro taking advantage of non-portable assumptions.)

Ok, so you want to enhance the language so offsetof() *can* be
implemented as a function (something you didn't mention in your
initial post). How would you do that? Can you show us a proposed
implementation of offsetof() as a function in an extended C?
How would the parameters be declared? How would the body of the
function refer to them?

As for assert(), it's a macro because it needs to refer to the values
of __FILE__, __LINE__, and __func__ *at the point of the call*.
This is source-level information that is not available to functions.
Permitting type names as function parameters wouldn't help.
How would you write assert() as a function in an extended ?

va_arg(), va_copy(), va_end(), va_start(): Same questions.

Oh, and setjmp() saves its calling environment; how would you write
that in an extended C?

If you want to require all these things to be functions, you're
going to have to show us how.
 
S

Seebs

FWIW, sandeep, I have not yet seen a suggestion from you that one would
have to *look* for reasons to oppose. In this case, the reasons to
oppose it have broken into the FBI's computers so they can look up our
home and work addresses and send us threatening letters. Also, they
are breaking into our offices and photocopying their body parts. We are
not looking for them; they are looking for us.
You want to totally reinvent the language into something quite different,
just so some built-in macros can be functions instead? (And after that you
will presumably ask why statements cannot also be implemented as functions.)

To make that work at runtime, runtime code would have to have access to
the entire type system, when the entire POINT of a statically typed
compiled language is to GET AWAY FROM THAT.

If you want dynamic typing, you are probably not looking for C.
I don't see how it would help. Any 'type arguments' you see in templates
aren't runtime values.

Well, that's the thing. They'd have to be, meaning that C would have
turned into a fully dynamic runtime language. Which is, well.

I love languages like that. I program in several of them. They're not C.
With getc(), that is easy enough to arrange without turning the entire
language upside-down.

Yes.

-s
 
I

Ian Collins

FWIW, sandeep, I have not yet seen a suggestion from you that one would
have to *look* for reasons to oppose. In this case, the reasons to
oppose it have broken into the FBI's computers so they can look up our
home and work addresses and send us threatening letters. Also, they
are breaking into our offices and photocopying their body parts. We are
not looking for them; they are looking for us.



To make that work at runtime, runtime code would have to have access to
the entire type system, when the entire POINT of a statically typed
compiled language is to GET AWAY FROM THAT.

If you want dynamic typing, you are probably not looking for C.


Well, that's the thing. They'd have to be, meaning that C would have
turned into a fully dynamic runtime language. Which is, well.

Not in the C++ meaning of "templates". All the instantiation magic
occurs at compile time when the types are known.
 
M

Mark Wooding

[much sense, and this...]
Oh, and setjmp() saves its calling environment; how would you write
that in an extended C?

I don't think one has to be able to write `setjmp' in C. It's certainly
not possible in strictly conforming C, but there are other standard
library functions which can't be implemented in strictly conforming C
either -- such as `exit' -- so that's not a useful criterion. I don't
see offhand why it might be impossible to implement `setjmp' and
`longjmp' in really awful platform-specific C.

The GNU libc actually appears to implement `setjmp' as a function, which
at least saves me the effort of demonstrating possibility.

-- [mdw]
 
S

Seebs

Not in the C++ meaning of "templates". All the instantiation magic
occurs at compile time when the types are known.

Hmm. True. I guess I was just thinking about writing an actual function
which takes a type as an argument, rather than a meta-language thing which
takes a type, but is not a function, but uses the type to generate a
function.

If offsetof() ought to be implementable as a function, then it needs to
really be dynamic. If we're just templating it, it's still an out-of-band
thing which is done dynamically and there's no function you can extract
and call generically.

-s
 
K

Keith Thompson

I don't think one has to be able to write `setjmp' in C. It's certainly
not possible in strictly conforming C, but there are other standard
library functions which can't be implemented in strictly conforming C
either -- such as `exit' -- so that's not a useful criterion. I don't
see offhand why it might be impossible to implement `setjmp' and
`longjmp' in really awful platform-specific C.

The GNU libc actually appears to implement `setjmp' as a function, which
at least saves me the effort of demonstrating possibility.

I think you're right.
 
E

Eric Sosman

[...]
But the true point is that if the problem is not being able to pass type
names to functions, but being able to pass them to macros, why not
improve the language to allow *all* functions (both implementation and
user functions) to accept type names as arguments? This would also be
very helpful for type-generic / template-based programming which is now
very difficult in C.

Types aren't "passed" to macros. Nothing is passed to a macro. A macro
is expanded at compile time, which is the time when type information
exists.[...]

Just to sharpen the point to greater keenness: Macros are
expanded at a time *before* types exist. That's why, for example,
you can't use #if to test the sizeof(something): sizeof can only
operate on things that have types, and at preprocessing time there
are as yet no types at all.
 
E

Eric Sosman

[...]
The vast majority of entities in the standard library that can
be invoked using syntax that looks like a function call *must*
be implemented as functions, and in addition *may* be implemented
as macros (which can be bypassed to get to the actual function).

Just one such entity, getc(), comes with permission for the macro
to evaluate its argument more than once.[...]

Nit: For sufficiently large values of "one," or if we decide
to ignore putc(). (I once knew a girl nicknamed "Putsi;" she was
nice. She was also rather large, and thus could have been called
a macro -- but she was nice, as I said, and no one with any sense
or sensitivity would have been so boorish. In any event, neither
Putsi nor putc() deserve to be ignored.)
 
K

Keith Thompson

Eric Sosman said:
[...]
The vast majority of entities in the standard library that can
be invoked using syntax that looks like a function call *must*
be implemented as functions, and in addition *may* be implemented
as macros (which can be bypassed to get to the actual function).

Just one such entity, getc(), comes with permission for the macro
to evaluate its argument more than once.[...]

Nit: For sufficiently large values of "one," or if we decide
to ignore putc(). (I once knew a girl nicknamed "Putsi;" she was
nice. She was also rather large, and thus could have been called
a macro -- but she was nice, as I said, and no one with any sense
or sensitivity would have been so boorish. In any event, neither
Putsi nor putc() deserve to be ignored.)

My apologies, putc(). You deserved better from me.
 
N

Nobody

Obviously the implementation can "work magic" and do anything by
functions.

No it can't. You're not talking about "functions", but "special forms".
Just because something uses the syntax "name(argument list)", that doesn't
make it a function.

There isn't a single *function* in the standard which requires special
treatment from the compiler. Anything which looks like a function either
can be implemented in a library on any sane platform or is a macro.
But the true point is that if the problem is not being able to pass type
names to functions, but being able to pass them to macros, why not
improve the language to allow *all* functions (both implementation and
user functions) to accept type names as arguments? This would also be
very helpful for type-generic / template-based programming which is now
very difficult in C.

If you want C++, you know where to find it.
 
E

Eric Sosman

setjmp and longjmp seem to be exceptions. For example, there are
requirements for the semantics of "volatile" when setjmp and longjmp
are called.

7.13p1: "The header <setjmp.h> defines the *macro* setjmp, ..."
(emphasis mine).
 

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,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top