1

Afaik NULL can be (or really is, at least in my stdlib implementation) #define'd as:

#define NULL ((void*)0)

also, https://stackoverflow.com/a/924683/668125 states that in C++ NULL is transparently cast to/from ((int)0) (which is the reason to use std::nullptr in C++ instead, since that has a real nil type/value pair thanks to the nullptr_t opaque typedef).

So, I'm currently developing a LuaJIT library and want to provide a helper function to check if a value is nil/NULL/whatever (=a value meaning nil but maybe not of type nil).

currently, that's:

function ffi.nil(value)
  return value==nil or value==ffi.NULL
end

but, a (NULL==0) in C would be true, as verified by this snippet printing true on my system:

#include <stdio.h>
#include <stdlib.h>
void main(void){
  if(NULL==0)
    printf("true\n");
  else
    printf("false\n");
}

so should I go for this definition of a "nil meaning value" instead?

function ffi.nil(value)
  return value==nil or value==ffi.NULL or value==0
end

TL;DR: in C, NULL is equal to 0, while in LuaJIT's FFI, no two pairs of nil, ffi.NULL, 0 are equal; so when defining what value should be considered a "nil like value" when dealing with 3rd party C libs, shall I include 0 or only nil or ffi.NULL?

Disclaimer: I'm afraid this might be considered an "opinion based question", so, in that case, I'll refine the question: Which behavior would more likely produce correct result, ignoring the fact that it could be considered good or bad style (so yes, if it's bad style but this particular style flaw is consistent between >50% of common libs, it's the way I'll have to do it)?

Community
  • 1
  • 1
nonchip
  • 1,084
  • 1
  • 18
  • 36

2 Answers2

6

value == nil will return true if value is a NULL cdata object.

LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2014 Mike Pall. http://luajit.org/
JIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse
> ffi = require "ffi"
> print(ffi.new("void*", nil) == nil)
true

Thus, there's no point in your ffi.nil function. Just do if value == nil.

Note:

  1. if value then won't work, because value is a cdata object and therefore evaluates to true, even though it is equal to nil. It's a bit confusing, but that's simply the way it is.

  2. Replacing builtin functions and modifying builtin library tables is usually bad practice. You should define it as a local function instead, or as a library function instead.

Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85
1

1. ABOUT NULL IN C

First, I analize what is NULL in C.

In the standard C99 document we can read, subsectiom 6.3.2.3:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.

This defines the null pointer constant. In every implementation the macro NULL has to be defined as the null pointer constant.

The macro NULL is defined in (and other headers) as a null pointer constant;

This means that there are only two possibilities to #define the macro NULL: 0 or (void*)0.

The null constant expression has two forms, as we see, but is not necessarilly considered a null pointer.
A conversion to a pointer type of the null pointer constant will bring a null pointer of that type.
The form (void*)0 is per se a null pointer of type void*.

Any two null pointers compare equal.

The equality operators are == and != and they allow to compare arithmetic values, as much as pointer values, by following precise rules that I don't copy here. However, I will cite this:

[For equality operators is allowed that] one operand is a pointer and the other is a null pointer constant.

So, every pointer can be compared against NULL to check equality.

(Observe that not only pointer to objects are allowed, but pointer to functions also can be compared against NULL).

If one operand is a pointer and the other is a null pointer constant, the null pointer constant is converted to the type of the pointer.

This describes how the comparison against NULL is performed, just in case.

Two pointers compare equal if [...] both are null pointers [...]

I cannot find the right place in the standard where a null pointer of some type, when compared against the null pointer constant, NULL, gives true. But, anyway, it is clearly intended that this is the expected behaviour.

We can conclude that, althoug every null pointer compared against 0 gives true, the 0 is not a null pointer, but an integer constant. The "real" null pointer value is not represented in any explicit way by the syntax of C, but only in indirect form.

2. WHAT TO DO IN LUA

Well, I don't know Lua, however because of you, I was looking around. There is some relation between Lua and C.

C has not a reserved word in the spirit of nil to represent null values.
The constant 0 is always an integer, not a pointer, but C compares it true against pointers having null value.
The NULL macro sometimes is defined as (void*)0, which is a pointer, but sometimes could be defined as merely 0, which again is an integer.
Since NULL is a macro, is not what really matters.

So, I think that none of the options you are thinking reflects what is happening in C.
However, in general, it is used NULL to designate the null pointer in C.
I saw C functions in Lua, called in some special way.
On the other hand, I infere from your question that some kind of .NULL thing can be invoked.

3. THE ANSWER

My opinion is that your choice has to be NULL.
Since you are planning to use that function to check null pointers in C, take in account that in C, the functions that return pointers also can return the null pointer, which, in turn, can be passed as an argument to another functions.
If your functions are expected to return also non-null values and/or to cooperate with another functions related to C pointers, the value NULL will have to be available.
This would be my choice.

Anyway, I apologize because I am guessing here, since I don't have knowledge about Lua.

pablo1977
  • 4,281
  • 1
  • 15
  • 41
  • I know both C and Lua, so what to do for each of them isn't the problem, but when defining a function to decide whether something is nil/NULL across language boundaries. the "kind of `.NULL` thing" you mention is a userdata containing "the" NULL (=`(void*)0` wrapped as Lua userdata) pointer in LuaJIT's ffi library (so you can compare it a C function's return value you called from within Lua). so I can use both `nil` to check for a Lua function's `nil` return value and `ffi.NULL` to check for a C function's `NULL` return. but should I then still check for `tonumber(value)==0`? – nonchip Jul 20 '14 at 09:22
  • If a C functions returns NULL, it means that its return type is "pointer to T", for some T. What is really returning is the "null value of type pointer to T". This value is not "0". As I have mentioned in my answer, `0` is always an integer constant, not a pointer value. This is explicitely stated in the standard C paragraph that I cited. So, you don't have to check for `tonumber(value)==0`. – pablo1977 Jul 20 '14 at 09:29
  • ok, the "An integer constant expression with the value 0, […] is called a null pointer constant." made me wonder if maybe there are implementations actually defining NULL as `(int)0`, but even in that case, LuaJIT (when compiled for the target implementation) would also use that for `ffi.NULL`, so you're right, thanks :) – nonchip Jul 20 '14 at 09:32
  • When the "null pointer constant" is defined as `0`, is not the "null pointer". This is funny, because the name "null pointer constant" suggest the contrary. The language C only "uses" the syntax `pointer == 0` to compare against the null pointer, but it is only a convention of the language. This doesn't mean that 0 can be considered a pointer. – pablo1977 Jul 20 '14 at 09:33
  • ok, so that's just another one of the many cases where C isn't as strictly typed as it claims to be :D (I remember hunting for about a week for that one segfault randomly occurring every few hours in a big GTK application, just to find a pointer cast overflowing) – nonchip Jul 20 '14 at 09:35