Can someone tell me (in noob-language) why this will compile for a Nano but not a Nano R4, and what I need to do to fix it?
#include <SPI.h>
#include <SdFat.h>
const int SD_CS = 8;
char csvChar = ""; // This is the line that causes an error
SdFat SD;
void setup() {
pinMode (SD_CS, OUTPUT);
while(!SD.begin(SD_CS));
}
void loop() {
}
Error message:
Compilation error: invalid conversion from 'const char*' to 'char' [-fpermissive]
I've stripped out nearly all of my sketch, and moved char csvChar = ""; from a function to a global declaration, but the error is still the same.
If I comment out that line, the sketch compiles for both Nano and Nano R4.
You are trying to assign a string constant to a single byte char. A string is not a char
Have you tried compiling the code on both boards with verbose reporting turned on in File/Preferences ? Do you see any warnings in the compiler output ?
As a matter of interest, which version of the SdFat library are you using ?
The issue is the same. The difference is that on R4, it's an error; while on AVR, it's just a warning. You can disable warnings, but you shouldn't. If you disable verbose output, you should still see the warning in red, before the "success" message indicating the used space:
sketch_sep11a.ino:4:16: warning: invalid conversion from 'const char*' to 'char' [-fpermissive]
char csvChar = "";
^~
Sketch uses 446 bytes (1%) of program storage space. Maximum is 30720 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.
On Widows and Linux, Preferences is under the File menu. On Mac, Settings is in the usual place, under the app name. Be sure the Compiler warnings is not None; it should be Default or higher.
A char is a single byte, to be interpreted as text. It uses a single quote. There must be something inside, you cannot have nothing. Double quotes are for a "string of char" or more accurately a C-string; which can have nothing, indicating an empty string.
In memory, a C-string is terminated by a NUL character, which has the numeric value zero. So that more is four bytes, with the values: 65, 9, 66, and 0. Like all C-string, the variable actually contains a pointer to those four bytes in memory.
@UKHeliBob If I turn on verbose reporting, there's a load of messages that mean nothing to me. What should I be looking for?
Compiling for both boards, the first thing in the console is in red (is that a warning?) and that is
loading library from C:\Users\idris\Documents\Arduino\libraries\LiquidCrystal_I2C-master: invalid library: no header files found
Which is odd to me, because there's no liquid crystal library called by the sketch.
Other than that, only compiling for the R4 produces anything in red, and that's the same Compilation error: invalid conversion from 'const char*' to 'char' [-fpermissive]
The compiler is looking for header files in all of your library folders and is warning that the LiquidCrystal_I2C-master library folder has no header files in it even though you are not using it
@kenb4 (I struggle to get my head round char and char arrays and strings and Strings.)
I understand that '\0' is like using zero to initialise and int.
So if I change char csvChar = ""; to char csvChar = '\0'; I don't get the compile error. Is that a valid solution or am I still missing the point?
Memory needs to put things in locations. char is (four bytes oops) of storage, the size of one "character" char* is "a pointer to" the first memory location in storage"...
...usually used with an "array of chars" like char* csvChar which can be written csvChar[] (notice the lack of a * and the use of [ ]... both of which can be arrays.
That would be the ampersand, & so &thing would be "the address of thing"
To put it another way: languages like Python and JavaScript don't have a separate type for characters. They just have a "string of length one", versus length zero, or length greater than one. There are functions to get the "character code" or numeric value of a given character in a string. With ASCII and Unicode, uppercase A is 65, TAB is 9, NUL is zero.
C/C++ and Java do have a separate char type, which has a single numeric value. (In Java, it's actually a 16-bit value to accommodate Unicode, but it turns out that's not actually big enough, now with all the extra emoji and such; oops.)
Depending on how you actually use it, you don't even have to initialize the variable when you declare it.
global variables are "initialized to zero"
a local variable will have a "random" value, whatever happens to be in memory at that point
depending on the flow of the code, if in all cases you assign a value to the variable before you read it, then the compiler should see that and not bother you with a warning
otherwise it should emit a warning
void loop() {
char c;
Serial.println(c);
}
On both AVR and R4; with warning level More or All, but not Default
sketch_sep11a.ino: In function 'loop':
sketch_sep11a.ino:20:17: warning: 'c' is used uninitialized in this function [-Wuninitialized]
Serial.println(c);
~~~~~~~~~~~~~~^~~
well — @InquisitiveMind phrasing is correct. The char * variable you define holds the address (its value is a pointer to a character).
As "ABC" 's type is const char * it's already a pointer, so already the address of something, in that case the address of its first character in memory, the 'A'
But you are right, the ampersand, & lets you indeed take the address of an existing item.
int x = 10;
int * const addressOfX = &x; // const because we only want to point to x. depends on use case
The direct reason of the error is a pure syntax mismatch. When declaring a single char , you must use a single quotes, whereas when describing a string, you have enclose it in a double quotes.
It is the true reason why your expression produces a compilation error.
That's relevant to the second part of the question ("What I need to do to fix it?"). The answer to the first part ("why this will compile for a Nano but not a Nano R4?") - the bit that really confused me - has, I think, only been addressed by @kenb4 and is:
Still get the warning unless those have been turned off
sketch_sep13a.ino:5:13: warning: invalid conversion from 'const char*' to 'char' [-fpermissive]
char c1 = one, c2 = two;
^~~
sketch_sep13a.ino:5:23: warning: invalid conversion from 'const char*' to 'char' [-fpermissive]
char c1 = one, c2 = two;
^~~
and then it prints
One
Two
15
19
115
119
the two C-strings, as usual
need to convert the char to int with the appropriate cast, so it gets printed as a number, in hexadecimal (which will be handy momentarily)
it so happens that the values here, below 0x20 (the space/blank character), are control characters: not printable anyway
the cast of the original pointers to uintptr_t, an "unsigned integer that can hold a pointer" requires the expect-you-know-what-you're-doing reinterpret_cast
When assigning to char, the pointer values get chopped to a single byte, in the usual way when you assign a wider number to a narrower variable.
So generally pointless, which is likely why in later compilers, it's considered an error.