When to check the return value of malloc

C

CBFalconer

Keith said:
The buffer behavior of getc should normally be identical to the buffer
behavior of fgetc. The only likely difference is the overhead of a
single function call for fgetc. If getc performs a system call to
refill the buffer every 1000 times, then fgetc performs a system call
to refill the buffer every 1000 times. (It's not clear whether their
behavior with respect to refilling the buffer is required to be
identical, but there's no reason for them to be different.)

Not so. The typical action of a getc macro will be something like:

#define getc(f) do { \
if (f->ix <= f->sz) return f->buf[f->ix++]; \
else return _getnew(f); \
} while (0)

totally avoiding all system calls until the buffer is emptied.
It's those intermediate system calls that can eat up the
performance. Of course there need not be any getc macro available
either.
 
F

Flash Gordon

CBFalconer wrote, On 02/02/08 22:02:
Keith said:
The buffer behavior of getc should normally be identical to the buffer
behavior of fgetc. The only likely difference is the overhead of a
single function call for fgetc. If getc performs a system call to
refill the buffer every 1000 times, then fgetc performs a system call
to refill the buffer every 1000 times. (It's not clear whether their
behavior with respect to refilling the buffer is required to be
identical, but there's no reason for them to be different.)

Not so. The typical action of a getc macro will be something like:

#define getc(f) do { \
if (f->ix <= f->sz) return f->buf[f->ix++]; \
^^^^^^
else return _getnew(f); \ ^^^^^^
} while (0)

I somehow hope that the getc macro looks significantly different to
that, since it should not be causing the function it is called from to
return! In the version of glibc on this machine it is simply
#define getc(_fp) _IO_getc (_fp)
Presumable _IO_getc is compiler magic.
totally avoiding all system calls until the buffer is emptied.
It's those intermediate system calls that can eat up the
performance. Of course there need not be any getc macro available
either.

I would normally use getc rather than fgetc just in case it is more
efficient (also it is one less character to type), but with modern
systems I would not actually expect any major difference.
 
I

Ian Collins

Flash said:
I would normally use getc rather than fgetc just in case it is more
efficient (also it is one less character to type), but with modern
systems I would not actually expect any major difference.

Just because it's a quiet Sunday afternoon, I just tried compiling this
with Sun cc:

#include <stdio.h>

int main() {
int n = getc( stdin );
}

The preprocessor output is:

int main()
{
int n =
(--((&__iob[0]))->_cnt<0?__filbuf((&__iob[0])):(int)*((&__iob[0]))->_ptr++);
}

Due to cc "knowing" and therefore being able to inline standard library
functions. I guess other compilers can do the same.
 
P

pete

Ian said:
Flash said:
I would normally use getc rather than fgetc just in case it is more
efficient (also it is one less character to type), but with modern
systems I would not actually expect any major difference.

Just because it's a quiet Sunday afternoon,
I just tried compiling this with Sun cc:

#include <stdio.h>

int main() {
int n = getc( stdin );
}

The preprocessor output is:

int main()
{
int n =
(--((&__iob[0]))->_cnt<0?__filbuf((&__iob[0])):(int)*((&__iob[0]))->_ptr++);
}

Due to cc "knowing"
and therefore being able to inline standard library
functions. I guess other compilers can do the same.

Are you sure getc isn't a macro on your Sun cc?

/* BEGIN new.c */

#include<stdio.h>

int main(void)
{

#ifdef getc
puts("getc is a macro.");
#else
puts("getc is not a macro.");
#endif

return 0;
}

/* END new.c */
 
R

Richard Tobin

Ian Collins said:
Just because it's a quiet Sunday afternoon, I just tried compiling this
with Sun cc:

#include <stdio.h>

int main() {
int n = getc( stdin );
}

The preprocessor output is:

int main()
{
int n =
(--((&__iob[0]))->_cnt<0?__filbuf((&__iob[0])):(int)*((&__iob[0]))->_ptr++);
}

Due to cc "knowing" and therefore being able to inline standard library
functions. I guess other compilers can do the same.

This is just because getc() is a macro. If it was an inline function,
you wouldn't see anything special in the preprocessor output. stdin is
probably also a macro expanding to &__iob[0].

-- Richard
 
C

CBFalconer

Flash said:
CBFalconer wrote, On 02/02/08 22:02:
.... snip ...
Not so. The typical action of a getc macro will be something like:

#define getc(f) do { \
if (f->ix <= f->sz) return f->buf[f->ix++]; \ ^^^^^^
else return _getnew(f); \ ^^^^^^
} while (0)

I somehow hope that the getc macro looks significantly different
to that, since it should not be causing the function it is called
from to return! In the version of glibc on this machine it is
simply #define getc(_fp) _IO_getc (_fp)
Presumable _IO_getc is compiler magic.
totally avoiding all system calls until the buffer is emptied.
It's those intermediate system calls that can eat up the
performance. Of course there need not be any getc macro
available either.

I would normally use getc rather than fgetc just in case it is
more efficient (also it is one less character to type), but with
modern systems I would not actually expect any major difference.

Notice the "something like" above. It was an explanation, not a
substitute. The thing you have to watch out for is that the getc
macro (and putc) is allowed to evaluate its operand more than
once. This is unique among all the system calls.
 
C

CBFalconer

Ian said:
Just because it's a quiet Sunday afternoon, I just tried
compiling this with Sun cc:

Its nowhere near Sunday afternoon here :)
#include <stdio.h>

int main() {
int n = getc( stdin );
}

The preprocessor output is:

int main()
{
int n =
(--((&__iob[0]))->_cnt<0?__filbuf((&__iob[0])):(int)*((&__iob[0]))->_ptr++);
}

Due to cc "knowing" and therefore being able to inline standard
library functions. I guess other compilers can do the same.

That macro is only usable on your particular installation. Here is
the gen:

7.19.7.5 The getc function

Synopsis
[#1]
#include <stdio.h>
int getc(FILE *stream);

Description

[#2] The getc function is equivalent to fgetc, except that
if it is implemented as a macro, it may evaluate stream more
than once, so the argument should never be an expression
with side effects.

Returns

[#3] The getc function returns the next character from the
input stream pointed to by stream. If the stream is at end-
of-file, the end-of-file indicator for the stream is set and
getc returns EOF. If a read error occurs, the error
indicator for the stream is set and getc returns EOF.
 
D

dj3vande

Keith Thompson wrote:
Not so. The typical action of a getc macro will be something like:
[...]

totally avoiding all system calls until the buffer is emptied.
It's those intermediate system calls that can eat up the
performance.

Here's the fgetc code from a real implementation:
--------
int
fgetc(FILE *fp)
{
return (__sgetc(fp));
}
--------
(<http://www.openbsd.org/cgi-bin/cvsw...c.c?rev=1.5&content-type=text/x-cvsweb-markup>)

Compare that with the macro definition of getc from the same
implementation:
--------
#define getc(fp) __sgetc(fp)
--------
(<http://www.openbsd.org/cgi-bin/cvsweb/src/include/stdio.h?rev=1.35&content-type=text/x-cvsweb-markup>, almost at the bottom)

Where are all those intermediate system calls? I think reality
disagrees with you here.


dave
 
C

CBFalconer

CBFalconer said:
Keith Thompson wrote:
Not so. The typical action of a getc macro will be something like:
[...]

totally avoiding all system calls until the buffer is emptied.
It's those intermediate system calls that can eat up the
performance.

Here's the fgetc code from a real implementation:
.... snip ...
Where are all those intermediate system calls? I think reality
disagrees with you here.

Nothing forces any implementation to supply such a macro. The
better systems do, if possible.
 
I

Ian Collins

CBFalconer said:
Its nowhere near Sunday afternoon here :)

We're way ahead of the pack down here!
That macro is only usable on your particular installation.
I know, the post was total bollocks, if I could have deleted it I would.
I should stick to sitting in the sun on Sundays...
 
I

Ian Collins

CBFalconer said:
Nothing forces any implementation to supply such a macro. The
better systems do, if possible.
I guess with C99, it (along with other trivial standard library
functions) could have been an inline function.
 
K

Keith Thompson

CBFalconer said:
Keith Thompson wrote: [...]
The buffer behavior of getc should normally be identical to the buffer
behavior of fgetc. The only likely difference is the overhead of a
single function call for fgetc. If getc performs a system call to
refill the buffer every 1000 times, then fgetc performs a system call
to refill the buffer every 1000 times. (It's not clear whether their
behavior with respect to refilling the buffer is required to be
identical, but there's no reason for them to be different.)

Not so. The typical action of a getc macro will be something like:

#define getc(f) do { \
if (f->ix <= f->sz) return f->buf[f->ix++]; \
else return _getnew(f); \
} while (0)

totally avoiding all system calls until the buffer is emptied.
It's those intermediate system calls that can eat up the
performance. Of course there need not be any getc macro available
either.

The details of your macro definition are a bit off (it won't have a
return statement, and a do-while statement can't appear in an
expression), but I get the idea. If there are any characters
remaining in the buffer, it simply returns the next one. If the
buffer is empty, it first fills it by performing a function call. If
the buffer is N bytes, then only 1 out of every N calls will require a
system call.

What makes you think that fgetc() won't do *exactly* the same thing?
Again, the only difference is the overhead of a single function call
(not a system call) for fgetc().
 
P

pete

CBFalconer said:
CBFalconer said:
Keith Thompson wrote:
The buffer behavior of getc should normally be identical to the
buffer behavior of fgetc.
Not so. The typical action of a getc macro will be something like:
[...]

totally avoiding all system calls until the buffer is emptied.
It's those intermediate system calls that can eat up the
performance.

Here's the fgetc code from a real implementation:
... snip ...
Where are all those intermediate system calls? I think reality
disagrees with you here.

Nothing forces any implementation to supply such a macro. The
better systems do, if possible.

The point that you are making,
in the case that when a getc macro is supplied:
that the getc function uses a system call and
that the getc macro doesn't,
is unfounded.

In cases when the getc macro is supplied,
then the getc function most likely
is nothing more than a wrapper
for either the getc macro or an equivalent macro.
 
P

pete

pete said:
Keith Thompson wrote:

The buffer behavior of getc should normally be identical to the
buffer behavior of fgetc.

Not so. The typical action of a getc macro will be something like:

[...]

totally avoiding all system calls until the buffer is emptied.
It's those intermediate system calls that can eat up the
performance.

Here's the fgetc code from a real implementation:
... snip ...
Where are all those intermediate system calls? I think reality
disagrees with you here.

Nothing forces any implementation to supply such a macro. The
better systems do, if possible.

The point that you are making,
in the case that when a getc macro is supplied:
that the getc function uses a system call and
that the getc macro doesn't,
is unfounded.

But I see that's not the point you're making.

The point that you are making,
in the case that when a getc macro is supplied:
that the fgetc function uses a system call and
that the getc macro doesn't,
is unfounded.

In cases when the getc macro is supplied,
then the fgetc function most likely
is nothing more than a wrapper
for either the getc macro or an equivalent macro.
 
C

CBFalconer

pete said:
CBFalconer said:
Keith Thompson wrote:

The buffer behavior of getc should normally be identical to
the buffer behavior of fgetc.

Not so. The typical action of a getc macro will be something
like:

[...]

totally avoiding all system calls until the buffer is emptied.
It's those intermediate system calls that can eat up the
performance.

Here's the fgetc code from a real implementation:
... snip ...
Where are all those intermediate system calls? I think reality
disagrees with you here.

Nothing forces any implementation to supply such a macro. The
better systems do, if possible.

The point that you are making,
in the case that when a getc macro is supplied:
that the getc function uses a system call and
that the getc macro doesn't,
is unfounded.

In cases when the getc macro is supplied, then the getc function
most likely is nothing more than a wrapper for either the getc
macro or an equivalent macro.

Not so. Note the provisions for multiple evaluation of the getc
parameter. Thus the macro may not be usable for some calls,
requiring the use of:

whatever = (getc)(f);

which avoids calling the macro.
 
C

CBFalconer

Keith said:
.... snip ..

What makes you think that fgetc() won't do *exactly* the same
thing? Again, the only difference is the overhead of a single
function call (not a system call) for fgetc().

That's going to be highly system dependent. The way to get the
most available performance is to use the getc macro if available
and suitable. Suitable has to do with the multiple evaluation of
parameters.
 
D

David Thompson

On Thu, 24 Jan 2008 11:00:01 GMT, Kelsey Bjarnason
Of course, if you simply used a size_t, which is the only sensible type
to use for that parameter, you wouldn't need the assertion in the first
place - the value could never be zero.
Unsigned could not be _less than zero_. It could be (passed as) zero,
and since real malloc() does allow zero, it can be and repeatedly has
been debated whether a malloc-wrapper should do so or not.

- formerly david.thompson1 || achar(64) || worldnet.att.net
 
K

Kelsey Bjarnason

On Thu, 24 Jan 2008 11:00:01 GMT, Kelsey Bjarnason

Unsigned could not be _less than zero_.

Indeed; I obviously intended "less than zero". Brain fart. :)
 
P

pete

CBFalconer said:
pete wrote:

Not so. Note the provisions for multiple evaluation of the getc
parameter. Thus the macro may not be usable for some calls,
requiring the use of:

whatever = (getc)(f);

which avoids calling the macro.

You're missing a point.
The multiple evaluation of an argument by a macro,
only makes a difference when the evaluation of
the argument has side effects.

Concerning the getc function,
the evaluation of the argument in a function call
will have side effects,
but the evaluation of the parameter object inside
of the function will not have side effects,
it's just a simple pointer object.
If the wrapper function then calls the macro,
then it won't matter if the macro evaluates
the argument 5 zillion times,
the side effects will only occur once.

The point is simpler to illustrate with putc than getc:

/* BEGIN new.c output */

The putc macro output, with 'X' as the int argument
when the stream argument outputs '0' as a side effect:00X

The putc_wrapper output, with 'X' as the int argument
when the stream argument outputs '0' as a side effect:0X

/* BEGIN new.c output */



/* BEGIN new.c */

#include<stdio.h>

int putc_wrapper(int c, FILE *stream)
{
return putc(c, stream);
}

int main(void)
{

#ifndef putc
puts("putc isn't a macro here and now.");
#else
puts("/* BEGIN new.c output */\n");
printf("The putc macro output, with 'X' as the int argument\n"
"when the stream argument outputs '0' as a side effect:");
putc ('X', (printf("0"), stdout));
puts("\n");
printf("The putc_wrapper output, with 'X' as the int argument\n"
"when the stream argument outputs '0' as a side effect:");
putc_wrapper('X', (printf("0"), stdout));
puts("\n\n/* BEGIN new.c output */");
#endif

return 0;
}

/* END new.c */
 

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
474,436
Messages
2,571,696
Members
48,796
Latest member
Greg L.
Top