Wot no bool?

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
CousinItt
Respected Member
Posts: 367
Joined: Wed May 31, 2017 6:55 pm

Wot no bool?

Post by CousinItt »

Hi all,

is there a boolean type in xc? I can't find one and the compiler complains if I try to use stdbool.h.

If there isn't, why?

Thanks!
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am

Post by mon2 »

.
Last edited by mon2 on Thu Jun 29, 2017 11:45 am, edited 1 time in total.
robertxmos
XCore Addict
Posts: 169
Joined: Fri Oct 23, 2015 10:23 am

Post by robertxmos »

Hi CousinItt,

There is no bool type in the XC language (although it is something that should be added and has been pending too long).
A true bool type is a one bit type (not 8 or 32) and is implicitly coerced to and from other integral types - thus there is a fair bit of work to do when adding it!
Until then, you must use one of the other integral types (e.g. int) and work with the coercion rules as with pre C99 e.g. '#define FALSE 0', '#define TRUE !FALSE'

robert

p.s. Using an integral with more than one bit does have the advantage that you can have alternative truths....
User avatar
CousinItt
Respected Member
Posts: 367
Joined: Wed May 31, 2017 6:55 pm

Post by CousinItt »

@mon2 ?

@robertxmos Thanks for the fulsome reply. That's exactly the type I'm looking for. I'm surprised it will take so much work, but I'm glad it's on the roadmap. As you suggest, I'll make do in the meantime.

p.s. groan
User avatar
aclassifier
Respected Member
Posts: 507
Joined: Wed Apr 25, 2012 8:52 pm

Post by aclassifier »

If I add #include <stdbool.h> and add -std=c99 or -std=gnu99 to the XCC flags, to me it complains about:

Code: Select all

error: use of undeclared identifer `_Bool'
So it seems like the compiler doesn't have _Bool as an intrinsic type, not even for C99?

In <stdbool.h> one could have

Code: Select all

defined(__GNUC__) && !defined(__STRICT_ANSI__) 
satisfied and I guess it will work, but that's not the setup, is it? In case, how are they set?

By the way, Robert, will there be a big difference between these three. I guess all will be autmatically coerced to int and then work. 1 is in the !FALSE set and should suffice(?):

Code: Select all

// A:
typedef enum {false,true} bool; // 0,1
// B:
#define FALSE 0
#define TRUE 1
// C:
#define FALSE 0
#define TRUE !FALSE
// D: from the above #ifdef in <stdbool.h>. I guess this assumes that "bool" is defined?
#define _Bool bool
#define bool  bool
#define false false
#define true  true
I have used A and B over the years, but C was new to me. Not even <stdbool.h> uses C. And D is really new to me! I don't even know how to interpret D!

I have a short chapter about bool (where <stdbool.h> is shown) and XC here: XC code examples (disclaimer: no money, no ads, no gifts. Only expenses and fun).
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/
robertxmos
XCore Addict
Posts: 169
Joined: Fri Oct 23, 2015 10:23 am

Post by robertxmos »

_Bool is available in 'C99' but not in 'xC', thus the header file <stdbool.h> won't work with 'xC'.

If you don't have a true 1bit type (xC and pre C99) and try to represent it using say a 32bit type, be careful when comparing against a literal representation e.g. 'TRUE'.
Whilst there may be only one 'FALSE' literal there may be many truths.... and my truth may be different from yours :-)
e.g.

Code: Select all

BOOL hasItem(Item i) {
   int i = findItemIndex(i);    // returns -1 if it is not there.
   return i+1;                 // if not there return 0, otherwise a value that can be converted to boolean true.
}

if (hasItem(i) == TRUE) { /* 32bit comparison is only true if index was '0' */ }

if (hasItem(i)) { /* convert to 1bit, hence all index values are true */ }
It is annoying that the compiler internally uses 1bit types (logical results & implicit conversion for conditional statements)
and yet the user can't explicitly use them in code - sorry.

robert
User avatar
aclassifier
Respected Member
Posts: 507
Joined: Wed Apr 25, 2012 8:52 pm

Post by aclassifier »

Important point!

However, I would have returned two values, {unsigned, bool} for {index, found} and in that case bool/found would always have been uniquely defined and both comparisons would be correct.

I think you state that A, B, C and D would all be wrong with the example you show?

Of course, with bool defined in the language then return i+1 would not be compilable. It's not bool. And if the type conversion were algorithmically wrong, that's the programmer's problem. In my opinion it's coding horror to return -1 on error anyhow, even if it's a coding standard all around.
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/
User avatar
aclassifier
Respected Member
Posts: 507
Joined: Wed Apr 25, 2012 8:52 pm

Post by aclassifier »

Triggered by Rober's important point earlier I made some code where that problem will not appear, and tested it. Along the line of my last comment.

However, I discovered something else, see USE_WRONG_RETURN_LIST. See in and below the code:

Code: Select all

#include <stdio.h>
#include <iso646.h> // For "not" etc

#define USE_BOOL_TYPEDEF // No difference since no type conversions done
#ifdef USE_BOOL_TYPEDEF
    typedef enum {false,true} bool; // 0,1
#else
    #define bool unsigned // long, int, unsigned, char, bool ok
    #define false 0
    #define true 1 // Or "not false"
#endif

typedef unsigned index_t; // long, int, unsigned, char, bool compile ok..
// #define USE_WRONG_RETURN_LIST  // ..with this defined

{index_t, bool} isItemIn (
    const char            search_for,
    const char            text[],
    static const unsigned len) {

    index_t  index     = 0;
    bool     found     = false;
    bool     searching = true;

    while (searching) {
        if (text[index] == search_for) {
            found     = true;
            searching = false;
        } else {
            index++;
            if (index == len) {
                searching = false;
            } else {} // No code, maybe next round
        }
    }
    return {index, found};
}

int main() {
    const char text[] = {'A','B','C','D','E','F','G','H','I','J'};
    index_t  index;
    bool     found;

    {index, found} = isItemIn ('C', text, sizeof(text));
    if (found) {
        printf("C found in %u\n", index);
    } else {
        printf("C not found\n");
    }
    #ifdef USE_WRONG_RETURN_LIST
        {found, index} = isItemIn ('X', text, sizeof(text));
    #else
        {index, found} =  isItemIn ('X', text, sizeof(text));
    #endif
    if (not found) {
        printf("X not found\n");
    } else {
        printf("X found in %u\n", index);
    }
    // LOG with
    // USE_WRONG_RETURN_LIST not defined
    // USE_BOOL_TYPEDEF or not no difference
    //   C found in 2
    //   X not found
    return 0;
}
Defining USE_WRONG_RETURN_LIST shows that the compiler will use any integer type for any definition I may have of bool. So, in this case I won’t get any help from the compiler. I may compile wrong code. I guess that’s not much worse than having any list of (..,signed,signed,..) parameter in any function, where (..,degC,degF,..) or (..,degF,degC,..) may be done wrongly. However, there is a small difference. With USE_WRONG_RETURN_LIST the compiler could have taken it if bool were understood by the compiler.

So, not even a typedef of the bool makes it a unique type to the compiler. It's still an integer-type type.

So, let's get real bool!-)
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/
robertxmos
XCore Addict
Posts: 169
Joined: Fri Oct 23, 2015 10:23 am

Post by robertxmos »

> So, not even a typedef of the bool makes it a unique type to the compiler. It's still an integer-type type.

Correct, typedef should be viewed as a handy alias.
One could argue that instead of tightening a type system it does the opposite!

If you want unique types you need to reach for struct/union (class if using c++ & interface if using xC)
Even 'enum' is weak (unlike the 'enum class' in c++11)
User avatar
aclassifier
Respected Member
Posts: 507
Joined: Wed Apr 25, 2012 8:52 pm

Post by aclassifier »

You are triggering me again!

Since interface is not for the below code, I collected the {index,found} into a struct. I guess it's less error prone since it's easier to asign x.index=index than x.index=found. Even if I don't do that, I do use it explicitly like isItemIn_return.index++. Doing it wrongly with isItemIn_return.found++ is easy to spot since I would think to increment a verb would ring a bell.

This uses the same amount of code and data as the above code. Maybe this indicates that the compiler also builds a struct for the parameter list? I kind of like it:

Code: Select all

#include <stdio.h>
#include <iso646.h> // For "not" etc

typedef enum {false,true} bool; // 0,1

typedef unsigned index_t; // long, int, unsigned, char, bool compile ok..

typedef struct { // easier to get right than the anonymous return parameter list
    index_t index;
    bool    found;
} isItemIn_return_t;

isItemIn_return_t isItemIn (
    const char            search_for,
    const char            text[],
    static const unsigned len) {

    isItemIn_return_t isItemIn_return = {0, false}; // Not type safe as {true, 0} will compile

    bool searching = true;

    while (searching) {
        if (text[isItemIn_return.index] == search_for) {
            isItemIn_return.found = true;
            searching = false;
        } else {
            isItemIn_return.index++;
            if (isItemIn_return.index == len) {
                searching = false;
            } else {} // No code, maybe next round
        }
    }
    return isItemIn_return;
}

int main() {
    const char text[] = {'A','B','C','D','E','F','G','H','I','J'};
    isItemIn_return_t isItemIn_retval;

    isItemIn_retval = isItemIn ('C', text, sizeof(text));
    if (isItemIn_retval.found) {
        printf("C found in %u\n", isItemIn_retval.index);
    } else {
        printf("C not found\n");
    }

    isItemIn_retval = isItemIn ('X', text, sizeof(text));

    if (not isItemIn_retval.found) {
        printf("X not found\n");
    } else {
        printf("X found in %u\n", isItemIn_retval.index);
    }
    // LOG with
    // USE_BOOL_TYPEDEF or not no difference
    //   C found in 2
    //   X not found
    return 0;
}
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/