DJI Neo drone app bugs and problems

Last Updated: 10/1/2024

NOTE: This article may be edited as new problems are found.

I just received my DJI Neo drone. This page will try to document various problems I have had with the DJI Fly iPhone app.

  • iOS App Version: 1.14.2 (on an iPhone 15 Pro)
  • Neo Firmware Version: 01.00.0300

Problems

Repeated Firmware Updates – So far, my DJI Neo has wanted to download a firmware update three times (maybe four). Each time, it completes, and tells me to restart the Neo. After that, the firmware remains 01.00.0300. Perhaps it is updating something else and this is a poorly worded message.

Connection Issues – Multiple attempts are needed almost every time I have tried to connect the phone to the Neo. I get the “Join network” iOS message, tap “Join”, and then it says it is unable to connect. When I check the WiFi settings of the phone, it shows it is connected to the DJI Neo’s WiFi hotspot.

Unable to Download Photos/Videos – There are two bugs here. One is that it just won’t download, and the workaround is shutting of cellular. That seems to help “most” of the time. The second issue is when you select photos/videos, but the “download” icon remains greyed out. Even killing the app and re-running it does not always make this work. Trail and error eventually makes it work for me.

Chinese (?) Pop-Up Message – I have no idea what this means, but I have seen it multiple times when “FlySafe requires update.” (And how often should this be updated? I’ve seen this message several times and I have only played with the drone yesterday and today, so far.)

    Various Lockups on Gallery Screen – Multiple times, I have seen the gallery screen become unresponsive. I cannot tap on anything. This usually happens when it is trying to download, and changes.

    Comments?

    If you have encountered any of these bugs, or different ones, please leave a comment with details. Thanks!

    More to be added…

    DJI Neo error downloading videos to phone

    And how to download them, in the first place…

    If you have a DJI Neo selfie drone, and you find yourself unable to download videos to your phone (in my case, an iPhone), try turning off Cellular Data. Once I did that, mine worked as expected.

    This is my first experience with a DJI product. I was surprised that the app was a bit clunky. I had difficulty trying to figure out how to batch download photos and videos. In case anyone else runs in to this, here are the steps:

    1. Connect the DJI Neo connected to the DJI Fly app. (Does yours work? Mine takes multiple attempts, even with the current latest firmware.)
    2. Select “Album” from the bottom left of the control screen. (Or, if you worry about accidentally flying the drone, you can exit out of the control screen and back to the connection screen and select it from there.)
    3. Select the Checkmark box near the top right. That will enable checkboxes on each thumbnail. You can tap just the ones you want, or…
    4. You may have to swipe down on the thumbnails to find it, but you can tap on the text “Batch Select“. That will check all the files.
    5. The bottom right will be a “download” icon. Tap that and your videos/photos will be downloaded in to your Photos app. (Does yours work? Mine has, once, but most of the time that icon remains greyed out.)
    6. To get out of this mode (so you can exit back to the control screen), you have to tape the checkbox at the top right again to turn off the image selection. It seems awkward that the “exit” goes away when you are in select mode.

    This app is clearly not ready for prime time, but the drone itself seems very neat. Actually, what it can do at this size and price point borders on “magic” in my eyes.

    More to come…

    printf portability problems persist… possibly.

    TL:DNR – You all probably already knew this, but I just learned about inttypes.h. (Well, not actually “just”; I found out about it last year for a different reason, but I re-learned about it now for this issue…)

    I was today years old when I learned that there was a solution to a bothersome warning that most C programmers probably never face: printing ints or longs in code that will compile on 16-bit or 32/64-bit systems.

    For example, this code works fine on my 16-bit PIC24 compiler and a 32/64-bit compiler:

    int x = 42;
    printf ("X is %dn", x);
    
    long y = 42;
    printf ("Y is %ldn", y);

    This is because “%d” represents and “int“, whatever that is on the system — 16-bit, 32-bit or 64-bit — and “%ld” represents a “long int“, whatever that is on the system.

    On my 16-bit PIC24 compiler, “int” is 16-bits and “long int” is 32-bits.

    On my PC compiler “int” is 32-bits, and “long int” is 64-bits.

    But int isn’t portable, is int?

    As far as I recall, the C standard says an int is “at least 16-bits.” If you want to represent a 16-bit value in any compliant ANSI-C code, you can use int. It may be using 32 or 64 bits (or more?), but it will at least hold 16-bits.

    What if you need to represent 32 bits? This code works fine on my PC compiler, but would not work as expected on my 16-bit system:

    unsigned int value = 0xaabbaabb;
    
    printf ("value: %u (0x%x) - ", value, value);
    
    for (int bit = 31; bit >= 0; bit--)
    {
        if ( (value & (1<<bit)) == 0)
        {
            printf ("0");
        }
        else
        {
            printf ("1");
        }
    }
    printf ("n");

    On a 16-bit system, an “unsigned int” only holds 16-bits, so the results will not be what one would expect. (A good compiler might even warn you about that, if you have warnings enabled… which you should.)

    stdint.h, anyone?

    In my embedded world, writing generic ANSI-C code is not always optimal. If we must have 32-bits, using “long int” works on my current system, but what if that code gets ported to a 32-bit ARM processor later? On that machine, “int” becomes 32-bits, and “long” might be 64-bits.

    Having too many bits is not as much of an issue as not having enough, but the stdint.h header file solves this by letting us request what we actually want to use. For example:

    #include <stdio.h>
    #include <stdint.h> // added
    
    int main()
    {
        uint32_t value = 0xaabbaabb; // changed
        
        printf ("value: %u (0x%x) - ", value, value);
        
        for (int bit = 31; bit >= 0; bit--)
        {
            if ( (value & (1<<bit)) == 0)
            {
                printf ("0");
            }
            else
            {
                printf ("1");
            }
        }
        printf ("n");
    
        return 0;
    }

    Now we have code that works on a 16-bit system as well as a 32/64-bit system.

    Or do we?

    There is a problem, which I never knew the solution to until recently.

    printf ("value: %u (0x%x) - ", value, value);

    That line will compile without warnings on my PC compiler, but I get a warning on my 16-bit compiler. On a 16-bit compiler, “%u” is for printing an “unsigned int”, as is “%x”. But on that compiler, the “uint32_t” represents a 32-bit value. Normal 16-bit compilers would probably call this an “unsigned long”, but my PIC24 compiler has its own internal variable types, so I see this in stdint.h:

    typedef unsigned int32 uint32_t;

    On the Arduino IDE, it looks more normal:

    typedef unsigned long int uint32_t;

    And a “good” compiler (with warnings enabled) should alert you that you are trying to print a variable larger than the “%u” or “%x” handles.

    So while this works fine on my 32-bit compiler…

    // For my 32/64-bit system:
    uint32_t value32 = 42;
    printf ("%u", value32);

    …it gives a warning on the 16-bit ones. To make it compile on the 16-bit compiler, I change it to use “%lu” like this:

    // For my 16-bit system:
    uint32_t value32 = 42;
    printf ("%lu", value32);

    …but then that code will generate a compiler warning on my 32/64-bit system ;-)

    There are some #ifdefs you can use to detect architecture, or make your own using sizeof() and such, that can make code that compiles without warnings, but C already solved this for us.

    Hello, inttypes.h! Where have you been all my C-life?

    On a whim, I asked ChatGPT about this the other day and it showed me define/macros that are in inttypes.h that take care of this.

    If you want to print a 32-bit value, instead of using “%u” (on a 32/64-bit system) or “%lu” on a 16-bit, you can use PRIu32 which represents whatever print code is needed to print a “u” that is 32-bits:

    #define PRIu32 "lu"

    Instead of this…

    uint32_t value = 42;
    printf ("value is %u\n", value);

    …you do this:

    uint32_t value = 42;
    printf ("value is %" PRIu32 "\n", value);

    Because of how the C preprocessor concatenates strings, that ends up creating:

    printf ("value is %lu\n", value); // %lu

    But on a 32/64-bit compiler, that same header file might represent it as:

    #define PRIu32 "u"

    Thus, writing that same code using this define would produce this on the 32/64-bit system:

    printf ("value is %u\n", value); // %u

    Tada! Warnings eliminated.

    And now I realize I have used this before, for a different reason:

    uintptr_t
    PRIxPTR

    If you try to print the address of something, like this:

    void *ptr = 0x1234;
    printf ("ptr is 0x%x\n", ptr);

    …you should get a compiler warning similar to this:

    warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘void *’ [-Wformat=]

    %x is for printing an “unsigned int”, and ptr is a “void *”. Over the years, I made this go away by casting:

    printf ("ptr is 0x%x\n", (unsigned int)ptr);

    But, on my 32/64-bit compiler, the “unsigned int” is a 32-bit value, and %x is not for 32-bit values. Thus, I still get a warning. There, I would use “%lx” for a “long int”.

    To make that go away, last year I learned about using PRIxPTR to represent the printf code for printing a pointer as hex:

    printf ("pointer is 0x%" PRIxPTR "\n",

    On my 16-bit compiler, it is:

    #define PRIxPTR "lx"

    This is because pointers are 32-bit on a PIC24 (even though an “int” on that same system is 16-bits).

    On the 32/64-bit compiler (GNU-C in this case), it changes depending on if the system:

    #ifdef _WIN64
    ...
    #define PRIxPTR "I64x" // 64-bit mode
    ...
    else
    ...
    #define PRIxPTR "x" // 32-bit mode
    ...
    #endif

    I64 is something new to me since I never write 64-bit code, but clearly this shows there is some extended printf formatting for 64-bit values, versus just using “%x” for the default int size (32-bits) and “%lx” for the long size.

    Instead of casting to an “(unsigned int)” or “(unsigned long int)” before printing, there is a special “uintptr_t” type that will be “whatever size a pointer is.

    This gives me a warning:

    printf ("ptr is 0x%" PRIxPTR "\n", (unsigned int)ptr);

    warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘unsigned int’ [-Wformat=]

    But I can simply change the casting of the pointer:

    printf ("ptr is 0x%" PRIxPTR "\n", (uintptr_t)ptr);

    You may have also noticed I still have a warning when declaring the pointer with a value:

    void *ptr = 0x1234;

    warning: initialization of ‘void *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]

    Getting rid of this is as simple as making sure the value is cast to a “void *”:

    void *ptr = (void*)0x1234;

    This is what happens when you learn C on a K&R compiler in the late 1980s and go to sleep for awhile without keeping up with all the subsequent standards, including one from 2023 that I just found out about while typing this up!

    Per BING CoPilot…

    • C89/C90 (ANSI X3.159-1989): The first standard for the C programming language, published by ANSI in 1989 and later adopted by ISO as ISO/IEC 9899:1990.
    • C95 (ISO/IEC 9899/AMD1:1995): A normative amendment to the original standard, adding support for international character sets.
    • C99 (ISO/IEC 9899:1999): Introduced several new features, including inline functions, variable-length arrays, and new data types like long long int.
    • C11 (ISO/IEC 9899:2011): Added features like multi-threading support, improved Unicode support, and type-generic macros.
    • C17 (ISO/IEC 9899:2018): A bug-fix release that addressed defects in the C11 standard without introducing new features.
    • C23 (ISO/IEC 9899:2023): The latest standard, which includes various improvements and new features to keep the language modern and efficient.

    The more you know…

    Though, I assume all the younguns that grew up in the ANSI-C world already know this. I grew up when you had to write functions like this:

    /* Function definition */
    int add(x, y)
    int x, y;
    {
    return x + y;
    }

    Now to get myself in the habit of never using “%u”, “%d”, etc. when using stdint.h types…

    Until then…

    Counting characters in a string in Color BASIC

    And so it begins…

    I want to visualize some playing card statistics, and the easiest way I could think of to do this was to write a program in BASIC. Of course.

    There are many approaches I can take, so as I put figure it out I will “show my work” and experiments that help me figure out which one will work best.

    For my task, I will greatly simplify a deck of cards by ignoring suits (I just care if it’s an Ace, a Five, a King or whatever). I figure I can store it as a 52-character string representing each card:

    A123456789JQKA123456789JQKA123456789JQKA123456789JQK

    I could “shuffle” this “deck” and end up with a string in “random” order. I believe I have touched on randomizing a list in the past, and had some great suggestions in comments on how to do it better. Forgetting all of that, let’s just say I end up with as string that gets randomized.

    But I digress…

    The next question will be: “How many Kings are left in the deck?”

    Some of you will already see I am heading down a poor path for doing this, but let’s start there anyway.

    One way of counting a specific character in a string is to loop through it and use MID$ to pull out an individual character. Something like this:

    FOR A=1 TO LEN(A$)
    IF MID$(A$,A,1)="S" THEN C=C+1
    NEXT

    That would count all the “S” characters that appear in the string. Since every time MID$ is used it has to build a new string representing that portion of the original string, this should be our slowest way to do this. On a system with tons of strings in use, string manipulation gets real slow. For such a simple program, this might be fast enough.

    Another approach, which was originally shown to me during a word wrap article as a submission, would be to use VARPTR to get the memory location of the 5-byte string ID memory, and then go to the memory where the string bytes are stored and use PEEK to look for them. You can find details in my earlier article on VARTPR.

    The memory location that VARPTR returns will have the length of string as the first byte (byte 0), then an empty byte (byte 1, always 0), then the next two bytes will be the address where the string is stored (bytes 2 and 3) followed by a zero (byte 4). Knowing this, something like this would do the same thing as MID$:

    A=VARPTR(A$)
    SL=PEEK(A)
    SS=PEEK(A+2)*256+PEEK(A+3)
    FOR A=SS TO SS+SL-1
    IF PEEK(A)=ASC("S") THEN C=C+1
    NEXT

    And do it faster.

    VARPTR is a legal BASIC function, but it still seems nasty to reach in to string memory to do this. Thus, I came up with the idea of using INSTR. This function returns the start location of a matching string in another string, or 0 if not found:

    PRINT INSTR("ABCDEFG","D")

    That should print 4, since a “D” is located at the 4th position in the string.

    You can also add an additional parameter which is where in the string to start searching. Doing this:

    PRINT INSTR(5,"ABCDEFG","D")

    …would print 0, because it starts scanning at the 5th character (just past the D) of the string, and then won’t find anymore.

    I could start using INSTR with a position of 1 (first character), and if it comes back with a value other than 0, I found one. That value will be the position of the found character. I could then loop back and use that position + 1 to scan again at the character after the match. Repeat until a 0 (no more found) is returned. That lets the scan for characters be done by the assembly code of the BASIC ROM and is even faster. It looks like this:

    F=0
    xxx F=INSTR(F+1,A$,T$):IF F>0 THEN C=C+1:GOTO xxx

    And we put them all together in a benchmark test program…

    10 ' COUNTSTR.BAS
    20 A$="THIS IS A STRING I AM GOING TO USE FOR TESTING. I WANT IT TO BE VERY LONG SO IT TAKES A LONG TIME TO PARSE."
    30 T$="S":T=ASC(T$)
    40 '
    50 ' MID$
    60 '
    70 PRINT "MID$:";TAB(9);
    80 TIMER=0:C=0
    90 FOR A=1 TO LEN(A$)
    100 IF MID$(A$,A,1)=T$ THEN C=C+1
    110 NEXT
    120 PRINT C,TIMER
    
    130 '
    140 ' VARPTR
    150 '
    160 PRINT "VARPTR:";TAB(9);
    170 TIMER=0:C=0
    180 A=VARPTR(A$)
    190 SL=PEEK(A)
    200 SS=PEEK(A+2)*256+PEEK(A+3)
    210 FOR A=SS TO SS+SL-1
    220 IF PEEK(A)=T THEN C=C+1
    230 NEXT
    240 PRINT C,TIMER
    
    250 '
    260 ' INSTR
    270 '
    280 PRINT "INSTR:";TAB(9);
    290 TIMER=0:C=0:F=0
    300 F=INSTR(F+1,A$,T$):IF F>0 THEN C=C+1:GOTO 300
    310 PRINT C,TIMER

    And running prints:

    Wow, using INSTR is six times faster than MID$? And four times faster than VARPTR. Nice.

    Now you know a bit about what I need to do. I need to represent cards in a deck (and be able to “draw” cards from that deck) and calculate how many of a specific card remain in the deck.

    Since I do not need to track or show the suits (hearts, spaced, clubs, diamonds), I figure I could use one byte in a string.

    To be continued … but in the meantime, do you have a better approach? Comment away!

    Splitting up strings in C source code.

    When printing out multiple lines of text in C, it is common to see code like this:

    printf ("+--------------------+\n");
    printf ("| Welcome to my BBS! |\n");
    printf ("+--------------------+\n");
    printf ("| C)hat    G)oodbye  |\n");
    printf ("| E)mail   H)elp     |\n");
    printf ("+--------------------+\n");

    That looks okay, but is calling a function for each line. You could just as easily combine multiple lines and embed the “\n” new line escape code in one long string.

    printf ("+--------------------+\n| Welcome to my BBS! |\n+--------------------+\n| C)hat    G)oodbye  |\n| E)mail   H)elp     |\n+--------------------+\n");

    Not only does it make the code a bit smaller (no overhead of making the printf call multiple times), it should be a bit faster since it removes the overhead of going in and out of a function.

    But man is that ugly.

    At some point, I learned about the automatic string concatenation that the C preprocessor (?) does. That allows you to break up quoted lines like this:

    const char *message = "This is a very long message that is too wide for "
        "my source code editor so I split it up into separate lines.\n";

    “Back in the day” if you had C code that went to the next line, you were supposed to put a \ at the end of the line.

    if ((something == true) && \
        (somethingElse == false) && \
        (somethingCompletelyDifferent == banana))
    {

    …but modern compilers do not seem to care about source code line length, so you can usually do this:

    printf ("+--------------------+\n"
            "| Welcome to my BBS! |\n"
            "+--------------------+\n"
            "| C)hat    G)oodbye  |\n"
            "| E)mail   H)elp     |\n"
            "+--------------------+\n");

    That looks odd if you aren’t aware of it, but makes for efficient code that is easy to read.

    However, not all compilers are created equally. A previous job used a compiler that did not allow constant strings any longer than 80 characters! If you did something like this, it would not compile:

    printf ("12345678901234567890123456789012345678901234567890123456789012345678901234567890x");

    I had to contact their support to have them explain the weird error it gave me. On that compiler, trying to do this would also fail:

    printf ("1234567890"
            "1234567890"
            "1234567890"
            "1234567890"
            "1234567890"
            "1234567890"
            "1234567890"
            "1234567890x");

    But that is not important to the story. I just mention it to explain that my background as an embedded C programmer has me limited, often, by sub-standard C compilers that do not support all the greatness you might get on a PC/Mac compiler.

    These days, I tend to break all my multi-line prints up like that, so the source code resembles the output:

    printf ("This is the first line.\n"
            "\n"
            "And we skipped a line above and below.\n"
            "\n"
            "The end.\n");

    I know that may look odd, but it visually indicates that there will be a skipped line between those lines of text, where this does not:

    printf ("This is the first line.\n\n"
            "And we skipped a line above and below.\n\n"
            "The end.\n");

    Do any of you do this?

    And, while today any monitor will display more than 80 columns, printers still default to this 80 column text. Sure, you can downsize the font (but the older I get, the less I want to read small print). Some coding standards I have worked under want source code lines to be under 80 characters, which does make doing a printout code review much easier.

    And this led me to breaking up long lines like this…

    printf ("This is a very long line that is too long for our"
            "80 character printout\n");

    That code would print one line of text, but the source is short enough to fit within the 80 column width preferred by that coding standard.

    And here is why I hate it…

    I have split lines up like this in the past, and created issues when I later tried to find where in the code some message was generated. For example, if I wanted to find “This is a very long line that is too long for our 80 character printout” and searched for that full string, it would not show up. It does not exist in the source code. It has a break in between.

    Even searching for “our 80 character” would not be found due to this.

    And that’s the downside of what I just presented, and why you may not want to do it that way.

    Thank you for coming to my presentation.

    Fantastic C buffers and where to find them.

    In my early days of learning C on the Microware OS-9 C compiler running on a Radio Shack Color Computer, I learned about buffers.

    char buffer[80];

    I recall writing a “line input” routine back then which was based on one I had written in BASIC and then later BASIC09 (for OS-9).

    Thirty-plus years later, I find I still end up creating that code again for various projects. Here is a line input routine I wrote for an Arduino project some years ago:

    LEDSign/LineInput.ino at master · allenhuffman/LEDSign (github.com)

    Or this version, ported to run on a PIC24 using the CCS compiler:

    https://www.ccsinfo.com/forum/viewtopic.php?t=58430

    That routine looks like this:

    byte lineInput(char *buffer, size_t bufsize);

    In my code, I could have an input buffer, and call that function to let the user type stuff in to it:

    char buffer[80];
    
    len = lineInput (buffer, 80); // 80 is max buffer size

    Though, when I first learned this, I was always passing in the address of the buffer, like this:

    len = lineInput (&buffer, 80); // 80 is max buffer size

    Both work and produce the same memory location. Meanwhile, for other variable types, it is quite different:

    int x;
    
    function (x);
    function (&x);

    I think this may be why one of my former employers had a coding standard that specified passing buffers like this:

    len = lineInput (&buffer[0], 80); // 80 is max buffer size

    By writing it out as “&buffer[0]” you can read it as “the address of the first byte in this buffer. And that does seem much more clear than “buffer” of “&buffer”. Without more context, these don’t tell you what you need to know:

    process (&in);
    process (in);

    Without looking up what “in” is, we might assume it is some numeric type. The first version passes the address in, so it can be modified, while the second version passes the value in, so if it is modified by the function, it won’t affect the variable outside of that function.

    But had I seen…

    process (&in[0]);

    …I would immediately think that “in” is some kind of array of objects – char? int? floats? – and whatever they were, the function was getting the address of where that array was located in memory.

    So thank you, C, for giving us multiple ways to do the same thing — and requiring programmers to know that these are all the same:

    #include <stdio.h>
    
    void showAddress (void *ptr)
    {
        printf ("ptr = %p\n", ptr);
    }
    
    int main()
    {
        char buffer[80];
        
        showAddress (buffer);
        
        showAddress (&buffer);
        
        showAddress (&buffer[0]);
    
        return 0;
    }

    How do you handle buffers? What is your favorite?

    Comments welcome…

    C escape codes

    Now maybe someone here can tell me if this makes any sense:

    #define SOME_NAME "SomeName\0"

    I ran across something like this in my day job and wondered what the purpose of adding a “\0” zero byte was to the end of the string. C already does that, doesn’t it?

    C escape codes

    I learned about using backslash to embed certain codes in strings when I was first learning C on my Radio Shack Color Computer. I was using OS-9/6809 and a pre-ANSI K&R C compiler.

    I learned about “\n” at the end of a line, and that may be the only one I knew about back then. (I expect even K&R has “\l” and maybe “\t” too, but I never used them in any of my code back then.)

    The wikipedia has a handy reference:

    Escape sequences in C – Wikipedia

    It lists many I was completely unaware of – like “vertical tab.” I’d have to look up what a vertical tab is, as well ;-)

    It was during my “modern” career that I learned you could embed any value in a printf by escaping it with “\x” and a hex value:

    int main()
    {
        const char bytes[] = "\x01\x02\x03\x04\x05";
        
        printf ("sizeof(bytes) = %zu\n", sizeof(bytes));
    
        for (int idx=0; idx<sizeof(bytes); idx++)
        {
            printf ("%02x ", bytes[idx]);
        }
        
        printf ("\n");
    
        return EXIT_SUCCESS;
    }

    This code makes a character array containing the bytes 0x01, 0x02, 0x03, 0x04 and 0x05. A zero follows, added by C to terminate the quoted string. The output looks like:

    sizeof(bytes) = 6
    01 02 03 04 05 00

    I do not know how I learned it, but it was just two jobs ago when I used this to embed a bunch of data in a C program. I believe I was tokenizing some strings to reduce code size, and I had some kind of lookup table of strings, and then the “token” strings of bytes that referred back to the full string. Something like this, except less stupid:

    #include <stdio.h>
    #include <stdlib.h> // for EXIT_SUCCESS
    #include <stdint.h>
    
    const char *words[] =
    {
        "I",
        "know",
        "you"
    };
    
    const uint8_t sentence[] = "\x01\x02\x03\x02\x01\x02";
    int main()
    {
        printf ("sizeof(sentence) = %zu\n", sizeof(sentence));
    
        for (int idx=0; idx<sizeof(sentence)-1; idx++)
        {
            printf ("%s ", words[sentence[idx]-1]);
        }
        
        printf ("\n");
    
        return EXIT_SUCCESS;
    }

    In this silly example, I have an array of strings, and then an encoded sentence with bytes representing each word. The encoded bytes will have a 0 at the end, so I use 1 for the first word, and so on, with 0 marking the end of the sequence. But, this example doesn’t actually look for the 0. It just uses the number of bytes in the sentence (minus one, to skip the 0 at the end) via sizeof().

    It really should use the 0, so this could be a function. You could pass it the dictionary of words, and the sentence bytes, and let it decode them in a more flexible/modular way:

    #include <stdio.h>
    #include <stdlib.h> // for EXIT_SUCCESS
    #include <stdint.h>
    
    // Dictionary of words
    const char *words[] =
    {
        "I",
        "know",
        "you"
    };
    
    // Encoded sentence
    const uint8_t sentence[] = "\x01\x02\x03\x02\x01\x02";
    
    // Decoder
    void showSentence(const char *words[], const uint8_t sentence[])
    {
        int idx = 0;
        
        while (sentence[idx] != 0)
        {
            printf ("%s ", words[sentence[idx]-1]);
            
            idx++;
        }
        
        printf ("\n");
    }
    
    // Test
    int main()
    {
        printf ("sizeof(sentence) = %zu\n", sizeof(sentence));
    
        showSentence (words, sentence);
    
        return EXIT_SUCCESS;
    }

    But I digress. My point is — I’m still learning things in C, even after knowing it since the late 1980s.

    So back to the original question: What is adding a “\0” to a string doing? This is one advantage of using sizeof() versus strlen(). strlen() will stop at the 0, but sizeof() will tell you everything that is there.

    #include <stdio.h>
    #include <stdlib.h> // for EXIT_SUCCESS
    #include <string.h> // for strlen()
    
    int main()
    {
        const char string[] = "This is a test.\0And so is this.\0And this is also.";
    
        printf ("strlen(string) = %zu\n", strlen(string));
    
        printf ("sizeof(string) = %zu\n", sizeof(string));
        
        return EXIT_SUCCESS;
    }

    The output:

    strlen(string) = 15
    sizeof(string) = 50

    If you try to printf() that string, it will print only up to the first \0. But, there is more “hidden” data after the zero. If you have the sizeof(), that size could be used in a routine to print everything. But why? We can already do string arrays or just embed carriage returns in a string if we wanted to print multiple lines.

    But it’s still neat.

    Have you ever done something creating with C escape codes? Leave a comment…

    Until then…

    C strings and pointers and arrays, revisited…

    Previously, I posted more of my “stream of consciousness” ramblings ending this bit of code:

    #include <stdio.h>
    #include <stdlib.h> // for EXIT_SUCCESS
    #include <string.h> // for strlen()
    
    int main()
    {
        const char *stringPtr = "hello";
        
        printf ("sizeof(stringPtr) = %ld\n", sizeof(stringPtr));
        printf ("strlen(stringPtr) = %ld\n", strlen(stringPtr));
    
        printf ("\n");
    
        const char string[] = "hello";
    
        printf ("sizeof(string) = %ld\n", sizeof(string));
        printf ("strlen(string) = %ld\n", strlen(string));
    
        return EXIT_SUCCESS;
    }

    Sean Patrick Conner commented:

    I would expect the following:

    sizeof(stringPtr) = 8; /* or 4 or 2, depending upon the pointer size */
    strlen(stringPtr) = 5;

    sizeof(string) = 6; /* because of the NUL byte at the end */
    strlen(string) = 5;

    – Sean Patrick Conner

    Sean sees things much more clearly than I. When I tried it, I was initially puzzled by the output and had to get my old brain to see the obvious. His comments explain it clearly.

    These musings led me to learning about “%zu” for printing a size_t, and a few other things, which I have now posted here in other articles.

    I learn so much from folks who take time to post a comment.

    More to come…

    My 360 photo/video (VR) experiments…

    I often forget to cross-post things between my project sites, so let’s do that right now.

    I bought my first digital camera (an Epson PhotoPC) in 1996. I have had many others since then. In addition to photo cameras, I also had various camcorders including my first digital camcorder in 1999. It recorded digitally to 8mm video tapes (Digital8 was the format, I believe). I have also experimented in 3-D, with a NuView camcorder attachment (what a beast that was) and some other gadgets, and some 360 photography.

    For 360 photos, you could originally just use a normal camera and take photos in all directions then “stitch” them together using special software. You can find examples of that in some 2002 photos I took at an Illinois Renaissance festival.

    There was an early attempt to do “one shot” 360 photos by using a half mirror ball on a rod, and attaching that to the lens of a camera. You would shoot with the camera pointed up, which captured the mirror ball and all things going on around it. Those images could be processed back to panoramas with special software. I had a gadget called SurroundPhoto I experimented with back around 2005.

    In the mid-2010s we started seeing consumer 360 cameras made by companies like Giroptic, RICHO and even Kodak. I have had a variety of those in recent years and am currently using an Insta360 X4.

    Sharing 360 photos and videos is not easy. Facebook supports them, and YouTube supports video, so I created some Facebook Groups for sharing photos (I made them groups so others could share theirs’s as well) and new YouTube channels for sharing videos.

    If you have ended up on my site for Insta360 topics, maybe you will want to pop by these groups/channels…

    VR videos on YouTube:

    VR photos on Facebook (post your own there, too):

    Until next time…

    Yes, Virginia. You CAN printf a size_t! And pointers.

    I always learn from comments. Sadly, I don’t mean the comments inside the million lines of code I maintain for my day job — they usually don’t exist ;-)

    I have had two previous posts dealing with sizeof() being used on a string constant like this:

    #define VERSION "1.0.42-beta"
    printf ("sizeof(VERSION) = %d\n", sizeof(VERSION));

    Several comments were left to make this more better.

    Use %z to print a size_t

    The first pointed out that sizeof() is not returning a %d integer:

    sizeof does not result in an int, so using %d is not correct.

    – F W

    Indeed, this code should generate a compiler warning on a good compiler. I would normally cast the sizeof() return value to an int like this:

    printf ("sizeof(VERSION) = %d\n", (int)sizeof(VERSION));

    BUT, I knew that really wasn’t a solution since that code is not portable. An int might be 16-bits, 32-bits or 64-bits (or more?) depending on the system architecture. I often write test code on a PC using Code::Blocks which uses the GNU-C compiler. On that system, I would need to use “%ld” for a long int. When that code is used on an embedded compiler (such as the CCS compiler for PIC42 chips), I need to make that “%d”.

    I just figured printf() pre-dates stuff like that and thus you couldn’t do anything about it.

    But now I know there is a proper solution — if you have a compiler that supports it. In the comments again…

    … when you want to print a size_t value, using %zu.

    – Sean Patrick Conner

    Thank you, Sean Patrick Conner! You have now given me new information I will use from now on. I was unaware of %z. I generally use the website www.cplusplus.com to look up C things, and sure enough, on the printf entry it mentions %z — just in a separate box below the one I always look at. I guess I’d never scrolled down.

    cplusplus.com/reference/cstdio/printf/

    This old dog just learned some new tricks!

    int var = 123;
    
    printf ("sizeof(var) = %zu\n", sizeof(var));

    Thank you very much for pointing this out to me. Unfortunately, the embedded compiler I use for my day job does not support any of the new stuff, and only has a sub-set of printf, but the Windows compiler I use for testing does.

    Bonus: printing pointers for fun and profit

    I’d previously ran in to this when trying to print out a pointer:

    int main()
    {
        char *ptr = 0x12345678;
        
        printf ("ptr = 0x%x\n", ptr);
    
        return EXIT_SUCCESS;
    }

    A compiler should complain about that, like this:

    warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘char *’ [-Wformat=]

    …so I’d just do a bit of casting, to cast the pointer to what %x expects:

    printf ("ptr = 0x%x\n", (unsigned int)ptr);

    BUT, that assumes an “int” is a certain size. This casting might work find on a 16-bit Arduino, then need to be changed for a 32-bit or 64-bit PC program.

    And, the same needs to be done when trying to assign a number (int) to a char pointer. This corrects both issues, but does so the incorrect way:

    int main()
    {
        char *ptr = (char*)0x12345678;
    
        printf ("ptr = 0x%lx\n", (unsigned long)ptr);
    
        return EXIT_SUCCESS;
    }

    First, I had to cast the number to be a character pointer, else it would not assign to “char *ptr” without a warning.

    Second, since %x expects an “unsigned int”, and pointers on this sytem are long, I had to change the printf to use “%lx” for a long version of %x, and cast the “ptr” itself to be an “unsigned long”.

    Had I written this initially on a system that uses 16-bit ints (like Arduino, PIC24, etc.), I would have had to do it differently, casting things to “int” instead of “long.”

    This always drove me nuts, and one day I wondered if modern C had a way to deal with this. And, indeed, it does: %p

    This was something that my old compilers either didn’t have, or I just never learned. I only discovered this within the past five years at my current job. It solves the problems by handling a “pointer” in whatever size it is for the system the code is compiled on. AND it even includes the “0x” prefix in the output:

    int main()
    {
        char *ptr = (char*)0x12345678;
    
        printf ("ptr = %p\n", ptr);
    
        return EXIT_SUCCESS;
    }

    I suppose when I found there was a “real” way to print pointers I should have expected there was also a real way to print size_t … but it took you folks to teach me that.

    And I thank you.

    Until next time…