XC8 novice question

Novice question using MPLABx + XC8

If i define my_variable using;

#define my_variable 0b10000000

And then I use it in a function that expects a 'char';

void my_function(char i);

I get a compiler warning;

warning: (752) conversion to shorter data type

By changing the function prototype to expect an 'int' the warning goes away so I think the defined my_variable is being assigned as an 'int'

So my question is how or can I structure my define so the defined my_variable is assigned as a 'char'..

I cannot see anything useful in the mplabx documentation.

Thanks.

Reply to
rwood
Loading thread data ...

Why not explicitly cast the value to a "char" in the define-ition (*if* you expect to always use it as such)?

Note that you should decide if you do/don't care about signedness of the value (i.e., is this value 128 or -127?) as "char" can vary from implementation to implementation.

Reply to
Don Y

Hi Don, I tried using:

#define my_variable (char)0b10000000

and also:

#define my_variable ((char)0b10000000)

Both of which compile without issue but still the warning about converting to a shorter data type persists.

Thanks.

Reply to
rwood

Are there still some idiotic systems that are defining char as _signed_ ????

If we really have to use such outdated systems, why aren't we using 6 bit characters with all upper case (or all lower case) ? In fact why not use 5 bit Baudot as in Manchester computers ?

Reply to
upsidedown

Yes, there are "idiotic" systems that have signed plain char. Most older, bigger systems (x86, PPC, MIPS, etc.) seem to have char signed by default.

The way to handle it is to only ever use "char" when you really mean a simple ASCII character. For anything else, use "uint8_t" or "int8_t" as appropriate. If you have a weird fascination for meaningless names, you can also use "unsigned char" or "signed char". But every time I see a function that takes a "char" and is not either a legacy C library function, or clearly looking for an ASCII character with a name like "debugPrintChar()", I know the code is bad.

Reply to
David Brown

I suspect that on your system, "char" is signed by default. When you write a number like 0b10000000, it is an "int" (unless it is outside the range of "int", in which case it gets bumped up to the first match of unsigned int, long int, unsigned long int, long long int, unsigned long long int). By casting it to "char", you are asking the compiler to fit the value 128 into a type with a range -128 to 127 (assuming I am right that char is signed on your system). That is causing the warning.

Never use "char" for numbers. It is /always/ the wrong type - its signedness will vary from system to system, and the name does not match the usage. And if your code might be used on other systems, remember that on some DSPs "char" is not 8 bits. Use "uint8_t" or "int8_t" as appropriate for numbers (or "uint_least8_t" and "int_least8_t" for very portable code).

So:

#define my_variable ((uint8_t) 0b10000000) void my_function(uint8_t i);

Also consider:

static const uint8_t my_variable = 0b10000000;

instead of the #define, unless you really need it to be a #define'd value (such as to give the size of an array, or because you have a crap compiler).

Reply to
David Brown

Am 11.09.2016 um 12:56 schrieb snipped-for-privacy@downunder.com:

Given that such systems are explicitly allowed by the C standard, there's nothing particularly idiotic about them.

But are there still idiotic programmers who use plain "char" in situations where they care about signedness? Well, yes, there are. Which is why coding standards such as MISRA forbid using plain char.

For starters: because those _are_ forbidden under the rules of the language.

Anyway, making plain char unsigned does not really solve any problem, so IMHO it's by no means idiotic to keep it signed.

It may appear to provide a solution to the issue: "How to keep non-ASCII characters in a plain char?" Except that it does so very incompletely, at best, because there are way more non-ASCII characters than an 8 bits unsigned char can possibly hold.

If one designed a new language like C today, 'char' would probably be called 'byte', or it would be emitted in favour of {u,}int8_t, whereas char would be 16 or 32 bits wide, and character and string constants UTF-8. But that's 20/20 hind sight, 30 years after the fact.

Reply to
Hans-Bernhard Bröker

Am 11.09.2016 um 09:02 schrieb rwood:

That's a blatant misnomer, because that's not at all a variable. It's a constant-valued macro. The distinction is important, so maybe you should go back to your training materials to learn more.

Of course you do. Another subject to look up in the books: what is the type of an integer constant? You'll have to check the compiler manual here, too, because that's non-standard syntax in your constant.

It's not assigned at all. Please learn about the difference between the preprocessor and the compiler proper.

Reply to
Hans-Bernhard Bröker

While this have been true for more than 30 years ago when everything was 7 bit ASCII or at least ISO646,

Of course EBCDIC had also some extended ranges.

Later on, VT220 multinational and later on Latin1 character sets utilized the while 8 bit range as a single _unsigned_ linear range.

Unsigned char was the answer for at least 5-10 years before UCS2.

That is true.

For correctly storing Unicode characters, a 21 bit data type is required.

There are some more or less workarounds for storing these Unicode characters, such as UTF-8 (1-3 bytes), UTF-16 (2-4 bytes) or as I once suggested UTF-64 on the Unicode list (three 21 bit characters in a 64 bit computer word e.g. Itanium.

that would be OK. {u,}int8_t, please.

actually 21 bit values.

UTF-8 is a quite reasonable compromize for most lnguages.

Having done IT applications for more than 30 years, the problem was well known in those days.

The video (dot matrix) display units of those days were not capable of displaying very good glyphs, but still good for Latin, Cyrillic or Arabic glyphs, but ware quite bad on Est-Asian glyphs.

Reply to
upsidedown

A drawback to this approach is it allows the OP to continue to think of it as a "variable". Either rename it ("my_constant" or "MY_CONSTANT") or use a manifest constant so each reference is ACTUALLY replaced with the PREPROCESSOR SUBSTITUTION: MY_CONSTANT = 7; (wrong!) becomes: 128 = 7; (which is CLEARLY wrong!)

[Time for bed...]
Reply to
Don Y

Not a problem with a PDS-1 (mid 70's vintage) -- *if* you could afford one! :>

Reply to
Don Y

Well, clearly he needs to pick a better name for his "variable". I don't know if he just picked a bad name, or if he is confused about variables and constants.

But if "my_variable" is declared as a "const", then writing "my_variable = 7" will give a compile-time error just as surely as it would with a pre-processor symbol.

Reply to
David Brown

Except, of course, that 0b10000000 == 512, which is probably the source of the original "warning: (752) conversion to shorter data type"

Everybody should occasionally re-read the "Frequently Questioned Answers"

formatting link

Reply to
Tom Gardner

Oops. Please ignore my dyslexia, or maybe my eyesight is going.

Reply to
Tom Gardner

Yes, but IME much easier to see whay you've done wrong (looking at the cpp(1) output).

Similar to writing: if (4 == count)... instead of: if (count == 4)...

Reply to
Don Y

I assume this is C11 we're talking about, or some vendor-specific C. At any rate, a #define is a preprocessor operation that just does a text substitution. So as far as the compiler itself is concerned, you didn't call

my_function(my_variable);

you called

my_function(0b10000000);

Since literal numerical constants default to type 'int' in C, this means that the compiler "sees" an int with a value that _just happens_ to be small enough to fit into a character.

Two good ways to get around this are to define my_variable as a const (really, it should be "my_constant"), or to use a cast:

static const char my_variable = 0b10000000;

OR

#define my_variable ((char)(0b10000000))

A halfway decent compiler will see the "static const" business and, unless you take the address of "my_variable" will just quietly turn it into a constant in the background, and optimize out actually putting it somewhere in memory.

--
Tim Wescott 
Control systems, embedded software and circuit design 
 Click to see the full signature
Reply to
Tim Wescott

Well, there may be differences of opinion here - and certainly experience and preferences are personal, making it hard to say "you are wrong".

But you are wrong.

Writing "if (4 == count)" is wrong. The last thing you need in your code is to write it backwards - it messes with your thinking, your writing, your reading and your understanding.

There are only three reasons why you would want to write "if (4 == count)". Either /all/ of these are true:

  1. You have trouble writing correct C code, even with the basic stuff (noting that everyone starts out as a beginner).
  2. You have a very poor quality compiler that can't check for such mistakes.
  3. You can afford to make mistakes and produce broken code, but can't afford software such as PC-Lint (or just gcc) to check such mistakes.
  4. You have no code reviews or other code quality control.
  5. You don't test your code, so don't see the consequences of the mistake.

/or/

You are required to program to a coding standard designed by numpties who make the assumptions above (i.e., MISRA - a mixture of good but mostly obvious ideas and a selection of downright bad ideas left over from the 90's).

/or/

You are small and green, and rely on the force. And when 900 years old /you/ are, speak normally /you/ will not.

No one looks at the C pre-processor output. There is no advantage in an error that could be found by look at it. If you declare your constant values as "const", then the compiler will stop with an error if you try to assign to them after initialisation. The error will be in the obvious place, and will be clear - you don't get better than that.

Reply to
David Brown

Actually, you raise a good point - 0b10000000 is hard to read. 0b constants are fine for small values, and okay for bigger values if there are plenty of 0's and 1's. But your eyes need a transition every 4 or 5 digits for clock recovery. So numbers like this are often better expressed as hex (0x80), or with shifts (1u

Reply to
David Brown

Yep - poor form on my part I should have referred to it as a constant rather than variable.

Reply to
rwood

Thanks to all who responded to my request for help.

I tried a few of the suggestions and ended up increasing the parameter expected by the function to an 'int'. It clears up all the warnings. I'd have preferred to have the constant cast as an 'char' but it seems the compiler won't play ball on doing that.

Thanks to all!

Reply to
rwood

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.