EmbeddedRelated.com
Forums

XC8 novice question

Started by rwood September 11, 2016
On 11-Sep-16 10:58 PM, David Brown wrote:
> On 11/09/16 16:32, Don Y wrote: >> On 9/11/2016 4:35 AM, David Brown wrote: >>> 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). >> >> 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...] >> >> > > 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. >
Yep - poor form on my part I should have referred to it as a constant rather than variable.
On 11-Sep-16 3:02 PM, rwood wrote:
> 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. > > >
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!
On 12/09/16 10:54, rwood wrote:
> On 11-Sep-16 3:02 PM, rwood wrote: >> 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. >> >> >> > > > 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!
If you learn anything from this thread, it should be that you never use "char" for numbers. Use "uint8_t" or "int8_t" depending on whether you want unsigned or signed types. This is /critical/ to writing good embedded software, especially on 8-bit devices.
On 9/11/2016 11:55 PM, David Brown wrote:
> On 11/09/16 22:15, Don Y wrote: >> On 9/11/2016 7:58 AM, David Brown wrote: >>> 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. >> >> 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)... > > 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:
No, the answer is much simpler than any of that! I started writing code in C (almost exactly) 40 years ago. Owning my first "personal" SysV machine more than 30 years ago. Compilers "back then" were far less "helpful" than what folks are used to using, today. And, far less "accessible" (imagine writing your code on a piece of PAPER and frantically typing it in when you get a chance -- so you can actually RUN it a few times, TODAY). Does your pen/paper "run lint"? [Do you remember when C didn't have a "void" type? Or, using '\!' and '\!!' in your sources? Or, when members of one type of struct had to have different names from any members of any OTHER structs (i.e., all tags shared a SINGLE namespace)?] And, over the years, have collected a bunch of compilers for oddball processors where the capabilities are essentially "take it or leave it -- no one else HAS a compiler for this processor!". If all your development has been for mainstream products, you're probably "spoiled" by the tools available! I would NOT, for example, write: x=-1; And, I *would* write: p = &buffer[0]; I'd use parens in places that you'd consider superfluous -- but that made bindings very obvious (cuz the compiler would do what I *told* it without suggesting that I might be doing something unintended): y = x / (*p); (*f)(); Or, lengthy expressions laid out as: foo = ( a + b ) / ( c * d ) - ( e % f ); And, to catch (some) '=' instead of "==" errors, write tests as: if ( CONSTANT == expression ) ... [would you consider "if (foo==bar())" as preferred to "if (bar()==foo)"?] Much of this is a consequence of how I learned to "read" (subvocalize) code to myself: x = y; is "x gets the value of y", not "x equals y". (how would you read x ::= y ?) if ( CONSTANT == expression ) is "if expression yields CONSTANT". Catching myself saying "if CONSTANT gets expression" -- or "if variable gets expression": if ( CONSTANT = expression ) if ( variable = expression ) is a red flag that I'm PROBABLY not doing what I want to do. I'll wager that most folks read: x = y; as: x equals y and subtly change their intent, but NOT their words, when encountering: if ( x == y ) as: if x equals y (how would they read "if ( x = y )"?) People reading my code never seem to have any problem understanding that: if ( NULL == malloc(...) ) is testing for a NULL result from malloc (i.e., "malloc yielding NULL"). [They also don't seem to find parallel loading a (hardware) counter with 0 as the same as "clearing" it.] This sort of "reading" makes it easy to discuss: (x, y) := cursor_position(); ("instantiate an x,y tuple with the current cursor position") vs. (x, y) = cursor_position(); ("the x,y tuple gets the current cursor position") or: x = cursor_X_coordinate(); ("x gets the cursor's X coordinate") What's important is consistency. It takes very little time for someone to pick up on a particular style -- if it is used CONSISTENTLY throughout a document/project. Ever notice code that walks an array using an index into the array; then, somewhere else, a pointer into it? As if the decision was arbitrary (or, made by someone other than the original developer -- having a different style?) Or, that refers to screen coordinates as "(x,y)" in some places, "(row,column)" in others (did you notice that row,column is really y,x?) and "(r,c)" in still others? You can read my code over the years and see the same style propagated throughout (discounting changes to the language, as alluded to earlier). It doesn't change when the "style du jour" comes -- and goes! -- along the way! (though identifiers have lengthened as the tools have supported them)
On 12-Sep-16 5:05 PM, David Brown wrote:
> On 12/09/16 10:54, rwood wrote: >> On 11-Sep-16 3:02 PM, rwood wrote: >>> 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. >>> >>> >>> >> >> >> 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! > > If you learn anything from this thread, it should be that you never use > "char" for numbers. Use "uint8_t" or "int8_t" depending on whether you > want unsigned or signed types. This is /critical/ to writing good > embedded software, especially on 8-bit devices. > > >
I've picked up quite a bit from this thread - as you can probably guess! I'll revisit my code and reassess the data types for all my variables. Thanks David.
On 12/09/2016 10:41, Don Y wrote:

<snip>

> And, to catch (some) '=' instead of "==" errors, write tests as: > if ( CONSTANT == expression ) ...
This is why I now write to this form. As someone who also writes VHDL where a single '=' is used in a conditional statement, it's all too easy to forget the '==' when reverting back to writing C. If, by accident, I write in 'c' if ( CONSTANT = expression ) I get a compiler error rather than getting entirely different behaviour to that intended. It is a style often recommended for safety critical applications. -- Mike Perkins Video Solutions Ltd www.videosolutions.ltd.uk
On 12/09/16 11:41, Don Y wrote:
> On 9/11/2016 11:55 PM, David Brown wrote: >> On 11/09/16 22:15, Don Y wrote: >>> On 9/11/2016 7:58 AM, David Brown wrote: >>>> 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. >>> >>> 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)... >> >> 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: > > No, the answer is much simpler than any of that! > > I started writing code in C (almost exactly) 40 years ago. Owning > my first "personal" SysV machine more than 30 years ago. > > Compilers "back then" were far less "helpful" than what folks > are used to using, today. And, far less "accessible" (imagine > writing your code on a piece of PAPER and frantically typing > it in when you get a chance -- so you can actually RUN it a few > times, TODAY). Does your pen/paper "run lint"?
Yes, long ago compilers had little in the way of helpful warnings or checks. And long ago, lint was not as good (though it's history is nearly 40 years old), and not as easily available. But /today/, there is no reason not to have reasonable error checking and warnings on your compiler. And if you compiler doesn't do a good enough job by itself, you can use PC-Lint, splint, or even gcc/clang for a different target in order to get good checking. (It's not needed here - XC8 will report "if (count = 4)" errors.)
> > [Do you remember when C didn't have a "void" type? Or, using '\!' > and '\!!' in your sources? Or, when members of one type of > struct had to have different names from any members of any > OTHER structs (i.e., all tags shared a SINGLE namespace)?]
The earliest C I have worked with is C89/C90/ANSI. It is fortunately rare that I have to work with such old tools, and I think it would be madness to limit my modern programming to suit such tools.
> > And, over the years, have collected a bunch of compilers for > oddball processors where the capabilities are essentially > "take it or leave it -- no one else HAS a compiler for this > processor!". If all your development has been for mainstream > products, you're probably "spoiled" by the tools available!
I have products for which there are /no/ decent C compilers, or at least products that could never have been made if we used the available compilers. And I have products where the only choices are poor or limited compilers. But for the most part, quality of tools is an important criteria when choosing a microcontroller.
> > I would NOT, for example, write: > x=-1;
Neither would I - I would write "x = -1;". But I believe I am missing your point with this example.
> And, I *would* write: > p = &buffer[0];
So would I - because I think the code looks clearer. When I want p to be a pointer to the first element of "buffer", that's what I write.
> I'd use parens in places that you'd consider superfluous -- but that > made bindings very obvious (cuz the compiler would do what I *told* it > without suggesting that I might be doing something unintended):
Me too. But that's for clarity of code for both the reader and the writer - not because I worry that my tools don't follow the rules of C.
> y = x / (*p);
Me too.
> (*f)();
I'd write f(); Though I'd use a better name than "f" for a function pointer, and I try to avoid function pointers where possible.
> Or, lengthy expressions laid out as: > foo = ( a + b ) > / ( c * d ) > - ( e % f ); >
If the expression were complicated enough, I would write: int x = a + b; int y = c * d; int z = e % f; foo = x / y - z;
> And, to catch (some) '=' instead of "==" errors, write tests as: > if ( CONSTANT == expression ) ...
No, I would /never/ write that. I would write it in a way that makes logical sense when reading or writing. You would say "if the number of apples is 3, the price is $1" - you would never say "if 3 is the number of the apples, $1 is the price". Thus I would always write: if (expression == constant) { .... } (I'm not a fan of shouting either - I left all-caps behind with BASIC long ago.) What benefit do you think "if (CONSTANT == expression)" gives you? Why is it useful to invert the logic and make code hard to read, just in case you make a mistake and write "if (expression = CONSTANT)"? It is highly unlikely that you would make such a mistake, and even less likely that you would make it and not find it quickly - and you compiler (or linter) will spot it for you.
> > [would you consider "if (foo==bar())" as preferred to "if (bar()==foo)"?] >
I'd usually try to avoid a function call inside an expression inside a conditional, but if I did then the guiding principle is to make it clear to read and understand.
> Much of this is a consequence of how I learned to "read" (subvocalize) > code to myself: > x = y; > is "x gets the value of y", not "x equals y". (how would you read x ::= > y ?) > if ( CONSTANT == expression ) > is "if expression yields CONSTANT". Catching myself saying "if CONSTANT > gets > expression" -- or "if variable gets expression": > if ( CONSTANT = expression ) > if ( variable = expression ) > is a red flag that I'm PROBABLY not doing what I want to do. > > I'll wager that most folks read: > x = y; > as: > x equals y
I can't say I vocalize code directly - how does one read things like brackets or operators like -> ? But "x = y" means "set x equal to y".
> and subtly change their intent, but NOT their words, when encountering: > if ( x == y ) > as: > if x equals y
"if x equals y", or "if x is equal to y".
> (how would they read "if ( x = y )"?)
I read it as "warning: suggest parentheses around assignment used as truth value" :-) It's simply a mistake, and I would not read it at all without mentioning the error.
> > People reading my code never seem to have any problem understanding > that: > if ( NULL == malloc(...) ) > is testing for a NULL result from malloc (i.e., "malloc yielding NULL"). >
Certainly people will know what the code does. That does not mean it is the clearest choice of code for the job.
> [They also don't seem to find parallel loading a (hardware) counter with > 0 as the same as "clearing" it.] > > This sort of "reading" makes it easy to discuss: > (x, y) := cursor_position(); > ("instantiate an x,y tuple with the current cursor position") vs. > (x, y) = cursor_position(); > ("the x,y tuple gets the current cursor position") or: > x = cursor_X_coordinate(); > ("x gets the cursor's X coordinate") > > What's important is consistency. It takes very little time for someone to > pick up on a particular style -- if it is used CONSISTENTLY throughout a > document/project. Ever notice code that walks an array using an index > into the array; then, somewhere else, a pointer into it? As if the > decision was arbitrary (or, made by someone other than the original > developer -- having a different style?) Or, that refers to screen > coordinates > as "(x,y)" in some places, "(row,column)" in others (did you notice that > row,column is really y,x?) and "(r,c)" in still others? > > You can read my code over the years and see the same style propagated > throughout (discounting changes to the language, as alluded to earlier). > It doesn't change when the "style du jour" comes -- and goes! -- along > the way! (though identifiers have lengthened as the tools have supported > them) >
My code style has been fairly similar over the 20 years I have been professionally programming C, as the guiding principles have been consistent. But a number of aspects have changed over time - when a change of style has made sense and led to better or clearer code, I have made that change. And when newer and better tools or language features have allowed better or clearer code, then I have embraced those features and changes. I certainly don't believe I started my career with a perfect style that must be maintained for ever. Consistency is a good thing - there's no doubt there. But it is not the overriding concern in all cases - breaking with old habits is necessary in order to improve. And remember, in this thread and context, we are giving advice to a new programmer. It is one thing to say that /you/ want to write "if (4 == count)" to remain consistent with the vast quantities of code you have written over the last 40 years. It is entirely different to consider how this /new/ programmer should write the vast quantities of code he will produce over the /next/ 40 years. /You/ have to live with the decisions from your past - the new programmer does not.
On 12/09/16 14:16, Mike Perkins wrote:
> On 12/09/2016 10:41, Don Y wrote: > > <snip> > >> And, to catch (some) '=' instead of "==" errors, write tests as: >> if ( CONSTANT == expression ) ... > > This is why I now write to this form. As someone who also writes VHDL > where a single '=' is used in a conditional statement, it's all too easy > to forget the '==' when reverting back to writing C. > > If, by accident, I write in 'c' > if ( CONSTANT = expression ) > I get a compiler error rather than getting entirely different behaviour > to that intended. >
If you write "if ( CONSTANT = expression )" by mistake in C, you get a compiler error. If the constant is not actually a constant, but a variable, you get a warning.
> It is a style often recommended for safety critical applications. >
No, it is a style recommended by people who think other people don't understand their tools properly. People writing safety critical applications will not make such mistakes because: 1. They are careful when writing their code. 2. They use as much static error checking as practically possible. That will always catch such errors. 3. They don't intentionally write code that looks like a mistake (such as "if (x = getNextItem()) ..." that might trigger warnings. 4. They have code reviews to help spot errors. 5. They have comprehensive testing. 6. They do not write code that reads backwards. 7. They do not rely on a rule like writing your conditionals backwards, which fails to work if the "constant" part is not actually declared constant. They prefer to rely on rules that actually /work/, such as requiring appropriate compiler static error checks. I'm all in favour of "defensive programming", and multiple defences to stop errors creeping in. But this particular case is just silly.
On 12/09/2016 13:56, David Brown wrote:
> On 12/09/16 14:16, Mike Perkins wrote: >> On 12/09/2016 10:41, Don Y wrote: >> >> <snip> >> >>> And, to catch (some) '=' instead of "==" errors, write tests as: >>> if ( CONSTANT == expression ) ... >> >> This is why I now write to this form. As someone who also writes VHDL >> where a single '=' is used in a conditional statement, it's all too easy >> to forget the '==' when reverting back to writing C. >> >> If, by accident, I write in 'c' >> if ( CONSTANT = expression ) >> I get a compiler error rather than getting entirely different behaviour >> to that intended. >> > > If you write "if ( CONSTANT = expression )" by mistake in C, you get a > compiler error. If the constant is not actually a constant, but a > variable, you get a warning. > >> It is a style often recommended for safety critical applications. >> > > No, it is a style recommended by people who think other people don't > understand their tools properly. > > People writing safety critical applications will not make such mistakes > because: > > 1. They are careful when writing their code.
Oh dear. We're all careful in writing code. The more careful, the less code. A bit like people who don't make any mistakes.
> 2. They use as much static error checking as practically possible. That > will always catch such errors.
Yes, they might give you a warning in the case "expression = CONSTANT" to see if that was intended.
> 3. They don't intentionally write code that looks like a mistake (such > as "if (x = getNextItem()) ..." that might trigger warnings.
As above.
> 4. They have code reviews to help spot errors.
I would hope that no such serious issues get this far.
> 5. They have comprehensive testing.
Of course.
> 6. They do not write code that reads backwards.
No. If it takes a second look for a reviewer to see what is intended, it can only make for safer code.
> 7. They do not rely on a rule like writing your conditionals backwards, > which fails to work if the "constant" part is not actually declared > constant. They prefer to rely on rules that actually /work/, such as > requiring appropriate compiler static error checks.
It's not a rule, its a style which is intended to remove silly errors.
> I'm all in favour of "defensive programming", and multiple defences to > stop errors creeping in. But this particular case is just silly.
Oh good, yet you seem to take a dislike to to others' defensive styles and methods. Is your way the only one everyone else must conform to? -- Mike Perkins Video Solutions Ltd www.videosolutions.ltd.uk
On 12/09/16 15:33, Mike Perkins wrote:
> On 12/09/2016 13:56, David Brown wrote: >> On 12/09/16 14:16, Mike Perkins wrote: >>> On 12/09/2016 10:41, Don Y wrote: >>> >>> <snip> >>> >>>> And, to catch (some) '=' instead of "==" errors, write tests as: >>>> if ( CONSTANT == expression ) ... >>> >>> This is why I now write to this form. As someone who also writes VHDL >>> where a single '=' is used in a conditional statement, it's all too easy >>> to forget the '==' when reverting back to writing C. >>> >>> If, by accident, I write in 'c' >>> if ( CONSTANT = expression ) >>> I get a compiler error rather than getting entirely different behaviour >>> to that intended. >>> >> >> If you write "if ( CONSTANT = expression )" by mistake in C, you get a >> compiler error. If the constant is not actually a constant, but a >> variable, you get a warning. >> >>> It is a style often recommended for safety critical applications. >>> >> >> No, it is a style recommended by people who think other people don't >> understand their tools properly. >> >> People writing safety critical applications will not make such mistakes >> because: >> >> 1. They are careful when writing their code. > > Oh dear. We're all careful in writing code. The more careful, the less > code. A bit like people who don't make any mistakes. >
I've seen more than enough code from different people to know that not everyone is careful when coding!
>> 2. They use as much static error checking as practically possible. That >> will always catch such errors. > > Yes, they might give you a warning in the case "expression = CONSTANT" > to see if that was intended.
Exactly. And usually you can choose to treat such warnings as errors.
> >> 3. They don't intentionally write code that looks like a mistake (such >> as "if (x = getNextItem()) ..." that might trigger warnings. > > As above.
Yes, "if (x = getNextItem())" will trigger the same warning. Style guides for safe programming often ban (or at least advise against) having expressions with side effects inside a conditional like this. If you /really/ want to write code like that, most compilers/linters will drop the warning if you use double parenthesis: if ((x = getNextItem())) ...
> >> 4. They have code reviews to help spot errors. > > I would hope that no such serious issues get this far.
That's what static error checking is for - catch the errors as early as possible.
> >> 5. They have comprehensive testing. > > Of course. > >> 6. They do not write code that reads backwards. > > No. If it takes a second look for a reviewer to see what is intended, it > can only make for safer code. > >> 7. They do not rely on a rule like writing your conditionals backwards, >> which fails to work if the "constant" part is not actually declared >> constant. They prefer to rely on rules that actually /work/, such as >> requiring appropriate compiler static error checks. > > It's not a rule, its a style which is intended to remove silly errors. > >> I'm all in favour of "defensive programming", and multiple defences to >> stop errors creeping in. But this particular case is just silly. > > Oh good, yet you seem to take a dislike to to others' defensive styles > and methods. Is your way the only one everyone else must conform to? >
I am happy with some defensive styles, unhappy with others. If the "defence" makes code harder to follow in some way, and does not add noticeably to the safety, then it is a bad idea. It is that simple. In this particular case, writing "if (1 == x)" instead of "if (x == 1)" adds absolutely /nothing/ to the "defence", if you already have sensible safe programming rules in place. And if you don't have such rules in place, this particular rule is a drop in the ocean at best, and false security at worst. Thus there is no defensive advantage in it. And while I am happy to accept that "code clarity" and "ease of understanding" are highly subjective issues, I think "if (1 == x)" reads backwards. It hinders comprehension. It might not hinder it much, but it hinders it a little. Thus there is a clear disadvantage to it. So I have no doubts that the "if (1 == x)" style is a bad idea overall. Any rule or style guideline should be considered in this way to see if it is a good idea or not. And the results are going to vary from programmer to programmer and project to project. If /you/ do your cost-benefit analysis and feel that "if (1 == x)" is a positive rule overall, then that's fine for you. It would surprise me, but that's fine.