How to specify a non-null pointer argument in C

J

jacob navia

Problem

You want to ensure that a pointer argument to a function
is non-null.

Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.

I wasn't aware of this till a discussion in comp.std.c
 
G

Guest

jacob said:
Problem

You want to ensure that a pointer argument to a function
is non-null.

Solution

Compare the pointer to a null pointer, and don't call the function if
they compare equal.

Problem

You want to assume that a pointer function parameter is non-null.
Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.

This ensures nothing, but allows certain otherwise invalid
optimisations, which may well be what you wanted. A minor point,
though:

#include <stdlib.h>

void f(double data[static 1]) {}
void g(double *data) {
if(data != NULL)
f(data);
}

int main(void) {
double x;
g(&x + 1);

double *p = malloc(1);
g(p);
free(p);
}

Both potential calls to f would be valid if "static 1" only meant
"non-null" and nothing more.
 
S

santosh

jacob said:
Problem

You want to ensure that a pointer argument to a function
is non-null.

Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.

I wasn't aware of this till a discussion in comp.std.c

How's the above to be extrapolated for the general case?

Isn't simply comparing against NULL a simpler approach?
 
H

hagman

jacob said:
Problem

You want to ensure that a pointer argument to a function
is non-null.

Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.

I wasn't aware of this till a discussion in comp.std.c

In what way then will

x = fn(p);

fail if p happens to be NULL?
 
J

jacob navia

hagman a écrit :
jacob navia schrieb:

Problem

You want to ensure that a pointer argument to a function
is non-null.

Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.

I wasn't aware of this till a discussion in comp.std.c


In what way then will

x = fn(p);

fail if p happens to be NULL?

The compiler can automatically insert a test in a
debug setting. For instance given this prototype

int fn(char string[static 1]);

when seeing a call
fn(s);
can replace that with

assert(s);
fn(s);

at each call site!
 
J

jacob navia

santosh a écrit :
jacob said:
Problem

You want to ensure that a pointer argument to a function
is non-null.

Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.

I wasn't aware of this till a discussion in comp.std.c


How's the above to be extrapolated for the general case?

Isn't simply comparing against NULL a simpler approach?

Obviously this is for the compiler. In a debug setting, a
compiler and replace
fn(s)
with
assert(s),fn(s);

given a prototype
char *fn(char str[static 1]);
 
J

jacob navia

Harald van Dijk a écrit :
jacob said:
Problem

You want to ensure that a pointer argument to a function
is non-null.


Solution

Compare the pointer to a null pointer, and don't call the function if
they compare equal.

Problem

You want to assume that a pointer function parameter is non-null.

Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.


This ensures nothing, but allows certain otherwise invalid
optimisations, which may well be what you wanted. A minor point,
though:

#include <stdlib.h>

void f(double data[static 1]) {}
void g(double *data) {
if(data != NULL)
f(data);
}

int main(void) {
double x;
g(&x + 1);

double *p = malloc(1);
g(p);
free(p);
}

Both potential calls to f would be valid if "static 1" only meant
"non-null" and nothing more.

I wasn't aware of this till a discussion in comp.std.c

well, you are right. That bug is not catched.
 
S

Serve Laurijssen

jacob navia said:
Problem

You want to ensure that a pointer argument to a function
is non-null.

Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.

I wasn't aware of this till a discussion in comp.std.c

what do you mean with ensure? I tried this code and I could easily call this
function with NULL. I didnt get a warning or error at all. And of course
this only happens at compile time right where the compiler can actually
analyse that it is called with NULL.

What about this then?
fn (malloc(1000000 * sizeof(double));

Seems to me we're stuck with if (p == NULL) for a while :)
 
K

Keith Thompson

hagman said:
jacob said:
Problem

You want to ensure that a pointer argument to a function
is non-null.

Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.

I wasn't aware of this till a discussion in comp.std.c

In what way then will

x = fn(p);

fail if p happens to be NULL?

By invoking undefined behavior.

C99 6.7.5.3p7:

If the keyword static also appears within the [ and ] of the array
type derivation, then for each call to the function, the value of
the corresponding actual argument shall provide access to the
first element of an array with at least as many elements as
specified by the size expression.

This "shall" appears outside a constraint, so if it's violated the
result is undefined behavior.

You might as well just (attempt to) dereference the pointer inside the
function; that invokes UB in exactly the same circumstances. And in
either case, a compiler may, but is not required to, insert a check
(and to decide what happens if the check fails).
 
J

jacob navia

Serve Laurijssen a écrit :
Problem

You want to ensure that a pointer argument to a function
is non-null.

Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.

I wasn't aware of this till a discussion in comp.std.c


what do you mean with ensure? I tried this code and I could easily call this
function with NULL. I didnt get a warning or error at all. And of course
this only happens at compile time right where the compiler can actually
analyse that it is called with NULL.

What about this then?
fn (malloc(1000000 * sizeof(double));

Seems to me we're stuck with if (p == NULL) for a while :)
This would provoke an assertion failure (if malloc returns NULL)

The compiler would automatically test for NULL *before* pushing the
arguments. In this case you would have an assertion failed NOT in the
fn function but in the calling function, where the error actually
is!

This is MUCH better than testing for NULL in 'fn'
 
K

Keith Thompson

jacob navia said:
Serve Laurijssen a écrit :
Problem

You want to ensure that a pointer argument to a function
is non-null.

Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.

I wasn't aware of this till a discussion in comp.std.c
what do you mean with ensure? I tried this code and I could easily
call this function with NULL. I didnt get a warning or error at
all. And of course this only happens at compile time right where the
compiler can actually analyse that it is called with NULL.
What about this then?
fn (malloc(1000000 * sizeof(double));
Seems to me we're stuck with if (p == NULL) for a while :)
This would provoke an assertion failure (if malloc returns NULL)

What assertion failure? Passing a null pointer to fn() invokes
undefined behavior; there is *no* required or implied check.
The compiler would automatically test for NULL *before* pushing the
arguments. In this case you would have an assertion failed NOT in the
fn function but in the calling function, where the error actually
is!

This is MUCH better than testing for NULL in 'fn'

A compiler *could* perform such a check, but if you want your code to
be portably robust, your only option is to do the check in your code.
 
S

Serve Laurijssen

jacob navia said:
How's the above to be extrapolated for the general case?

Isn't simply comparing against NULL a simpler approach?

Obviously this is for the compiler. In a debug setting, a
compiler and replace
fn(s)
with
assert(s),fn(s);

given a prototype
char *fn(char str[static 1]);

I agree its somewhat nice that there is a way to express that a pointer may
not be NULL and that a compiler can insert some assert then, but you just
cant rely on that all compilers will do this so the progger will have to
check himself too.
If you're planning to build this into your compiler, may I suggest that if
the code contains a manual NULL-pointer check that you omit the assert? :)
 
H

hagman

jacob said:
hagman a écrit :
jacob navia schrieb:

Problem

You want to ensure that a pointer argument to a function
is non-null.

Solution

int fn(double data[static 1]);

This means that the array (that is passed as a pointer)
must have at least 1 element, i.e. can't be NULL.

I wasn't aware of this till a discussion in comp.std.c


In what way then will

x = fn(p);

fail if p happens to be NULL?

The compiler can automatically insert a test in a
debug setting. For instance given this prototype

int fn(char string[static 1]);

when seeing a call
fn(s);
can replace that with

assert(s);
fn(s);

at each call site!

Maybe, but then it's at least no compile-time test, but rather a
runtime test.
Production code that might die with an "assertion failed: s in line
...." (in its debug version)
is not really more stable than code that dies with a segfault.

Thus I might as well have used the simpler idiom

int fn(char* string) {
assert(string);
...
}

Also, this is much clearer to me as the "char string[static 1]" trick
seems to suggest
to the unalert reader that the size of the array is exactly 1.
 
J

jacob navia

hagman a écrit :
Maybe, but then it's at least no compile-time test, but rather a
runtime test.
Production code that might die with an "assertion failed: s in line
..." (in its debug version)
is not really more stable than code that dies with a segfault.

It would crash not in the called function but in the calling function.
Big difference!
 
K

Keith Thompson

jacob navia said:
hagman a écrit :

It would crash not in the called function but in the calling function.
Big difference!

jacob, you *do* understand that it's not required to crash at all,
right? Given:

int fn(double data[static 1]);

the compiler is not obliged to insert any check at all.
 
J

jacob navia

Keith Thompson a écrit :
jacob navia said:
hagman a écrit :


It would crash not in the called function but in the calling function.
Big difference!


jacob, you *do* understand that it's not required to crash at all,
right? Given:

int fn(double data[static 1]);

the compiler is not obliged to insert any check at all.

Of course not. But it CAN do it legally.

This is a great progress, at least for me. I will change all headers
where the standard has

size_t strlen(const char *);

to

size_t strlen(const char[static 1]);

and I will insert tests for NULL when calling those functions
automatically!
 

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,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top