2

Is there C data type that is equivalent to Python None type?

I tried to search for it on the internet but I couldn't really find anything.

Thank you,

jschnieder
  • 191
  • 1
  • 8
  • Related: https://stackoverflow.com/questions/19473185/what-is-a-none-value – Jerry Jeremiah Jun 25 '20 at 00:50
  • 1
    C is statically typed, so a 'None' type really doesn't make any sense. There's a 'void' type which is really not at all the same thing. – Chris Dodd Jun 25 '20 at 00:53
  • For pointers there is always NULL. For float and double there is NaN. But for int, short, and long there is no value that you can assign that means the integer variable has no value - every sequence of bits is a valid number. So it doesn't work for every type. – Jerry Jeremiah Jun 25 '20 at 00:54
  • @JerryJeremiah FWIW, some architectures do exist where the integer types can have "invalid" values called [trap representations](https://stackoverflow.com/questions/6725809/trap-representation). Other than an `unsigned char`-based bit pattern and a `memcmp()`/`memset()` or similar, checking for or setting such values would likely be somewhat problematic. – Andrew Henle Jun 25 '20 at 01:12

1 Answers1

4

Python is dynamically typed so you can bind a variable name to any type, such as string, numeric, or NoneType. As C is statically typed, variables are locked to a specific type, but there's nothing stopping you from creating a type able to be any type.

For example, a union with a tag field to indicate the type, such as in the following complete program. First, the tag and union types which allow you to store and select any of the types:

enum uberType { ETYP_NONE, ETYP_INT, ETYP_DOUBLE, ETYP_CHARPTR };
typedef struct {
    enum uberType type;
    union { int valInt; double valDouble; char *valCharPtr; };
} tUberType;

Then some helper functions to set the uber-type to a specific typed value:

void makeNone(tUberType *ut) {
    ut->type = ETYP_NONE;
}

void makeInt(tUberType *ut, int val) {
    ut->type = ETYP_INT;
    ut->valInt = val;
}

void makeDouble(tUberType *ut, double val) {
    ut->type = ETYP_DOUBLE;
    ut->valDouble = val;
    }

void makeCharPtr(tUberType *ut, char *val) {
    ut->type = ETYP_CHARPTR;
    ut->valCharPtr = val;
}

And, finally, a test harness, including an output function:

#include <stdio.h>

void evalUber(tUberType *ut, char *post) {
    switch (ut->type) {
    case ETYP_NONE:
        printf("none:%s", post);
        break;
    case ETYP_INT:
        printf("int:%d%s", ut->valInt, post);
        break;
    case ETYP_DOUBLE:
        printf("double:%f%s", ut->valDouble, post);
        break;
    case ETYP_CHARPTR:
        printf("charptr:%s%s", ut->valCharPtr, post);
        break;
    default:
        printf("?%s", post);
        break;
    }
}

int main(void) {
    tUberType x;
    makeNone(&x); evalUber(&x, "\n");
    makeInt(&x, 42); evalUber(&x, "\n");
    makeDouble(&x, 3.14159); evalUber(&x, "\n");

    return 0;
}

The output of the test harness main is, as expected:

none:
int:42
double:3.141590
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953