invert (~) causes truncation warning?

Go To Last Post
30 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This line:
PORTB = ~0xff;
created this warning:
main.c:217: warning: large integer implicitly truncated to unsigned type

o It's easy to fix but should this warning be generated?
I think I can see what's happening;

PORTB = ~0x02; // generates this in the list:
199 008e 8EEF ldi r24,lo8(-2)
200 0090 88BB out 56-0x20,r24

PORTB = ~0xff; // generates this in the listing:
222 00ae 18BA out 56-0x20,__zero_reg__

So __zero_reg__ must be 16 bit? casting ~0xff to uint8_t works fine as does setting it to a positive value, 0x00 instead of inverting. I only inverted because it was easier to read. The LEDs on the SK500 are negative logic. It is only a warning after all and not an error. (like stop lights, they're just a suggestion).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
 PORTB = ~0x02; // generates this in the list:
199 008e 8EEF ldi r24,lo8(-2) 

Are you sure about this? I get "lo8(-3)", which is what I would expect.

 PORTB = ~0xff; // generates this in the listing:
222 00ae 18BA out 56-0x20,__zero_reg__ 

This is presumably what gave you the warning. Since ~0xFF is 0xFF00 (-256), chopping off the high 8 bits produces a result
whose sign is different from the original, thus the warning. I'm pretty sure there's an FAQ about this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks.
and yes it is the faq. I missed it on the first pass.
From the FAQ

Quote:

var &= ~mask; /* wrong way! */
var &= (unsigned char)~mask; /* right way */

It's faily explicit isn't it?

and you are of course right about the output. it is lo8(-3).

-Bryan

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If I remember correctly, GCC converts almost everything to an int while performing operations on it. You need to explicitly specify an unsigned char via casting.

Feel free to (gently) correct me on this.

- Dean :twsited:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No need to correct, since you're right about it.
This is not just the GCC way. The promotion to int is required by the C stanard, so any correct compiler will do it. I think the warning is optional though.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hurrah, I was right for once! Incidentally, would you just typecast the int back to an unsigned char, or what?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abcminiuser wrote:
Hurrah, I was right for once! Incidentally, would you just typecast the int back to an unsigned char, or what?

- Dean :twisted:


You don't need to, the unsigned char itself is not changed by the typecast, imagine a temporary copy of it being made for the purposes of the operation.
Say you had a variable of type unsigned char, it would only have one byte allocated in RAM, if the typecast actually promoted the variable, the compiler would need to shift everything about to make the extra space.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
abcminiuser wrote:
Hurrah, I was right for once! Incidentally, would you just typecast the int back to an unsigned char, or what?

- Dean :twisted:


You don't need to

IMO, You still should. Your goal should always be to compile without any warnings. Else, You stand the risk of getting numb to them and missing the important warning among all those non-important.

At work I'm using MS Visual C++. We keep the setting "Treat warnings as errors" (ie. no code generated, make stops before linking...) on at all times, forcing us to inspect every warning and "fix" it. One of my small tasks on my AVR-GCC-todo-list is to check if AVR-GCC has the correspoinding setting. If I find it i will immediately add it to the template makefile that comes with WinAVR. (Maybe even convince Joerg to handle it in Mfile?)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Johan, I'm not quite sure what you're saying here. I'm saying that if you you have a variable of type unsigned char and you need to cast it as an ]int in order to perform an operation, that it is not necessary to "uncast" it afterwards. Are you saying that it IS necessary? After all, in the original example the unsigned char was a constant, why would you need to "uncast" it afterwards, and what warning would you expect to get?
I have a feeling that we are totally misunderstanding each other here!

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
why would you need to "uncast" it afterwards, and what warning would you expect to get?

The original question was why

PORTB = ~0xff; 

generates a warning "large integer implicitly truncated to unsigned type". As Dean (abcminiuser) pointed out it's because the complement operator (~) procudes a 16-bit integer value. The warning then occurs when we try to assign such a value to PORTB which is 8 bits. In this context there is no danger in loosing data so, no it is not technically necessary to fix this one. The casting Dean discusses isn't a cast to a 16-bit value (that is done implicitly when the compiler sees the ~). What dean discusses is a cast of the result back to an unsigned char to prevent the warning the OP asked about.

My point was rather that You should not live with any warnings ever. Amongst all those warnings that point to probably harmless situations, as above, there may lurk a warning that You really should or must deal with. Such a waning might go unnoticed if You tend to live with seeing tons of warnings. Ie. if I get, say, 30 such warnings for a build do I read through them every time You build to see that they are all harmless? Probably not. I'm saying

1. I get rid of harmless warnings so I can see thos pointing to potentially harmful situations. And as I have to get rid of the latter also - I just get rid of all warnings. Then "no news is good news"...

2. As my character is far from perfect i tend to fall into reasoning like "Oh, I get a warning. I'll fix that soon..." and then I never fix it. Then I start to live with loads of warnings, and don't see the potentially harmful one coming. To prevent this from happening, I see to it that the build isn't successful if any warnings occur - forcing me to deal with all of them at once.

So my point was rather one of programming style than of what is nessecary to explain thechnically what the OP asked about (Dean did the latter).

Sorry for any confusion.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I agree 100%, compilation with no warnings should be the aim.
Likewise sorry for any confusion.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:

At work I'm using MS Visual C++. We keep the setting "Treat warnings as errors" (ie. no code generated, make stops before linking...) on at all times, forcing us to inspect every warning and "fix" it. One of my small tasks on my AVR-GCC-todo-list is to check if AVR-GCC has the correspoinding setting.

-Werror

JohanEkdahl wrote:

If I find it i will immediately add it to the template makefile that comes with WinAVR. (Maybe even convince Joerg to handle it in Mfile?)

Not for the next release. Not enough time. If you ask him, maybe for the release after that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I do not agree fully here ....
I sometimes do declare variables that i don't use until i get a loong way down in a routine. or do the

uint8_t  i,j,k,l,m;

just to have som locals for loopcounts etc.

I might hit compile before that , and would like to see my code compile correctly , and not produce an error.
I do verify that its just my unused variable warning. But still i think its a matter of taste.
I always get rid of the errors (solve) , before i "release" a program.

Its not an issue , as i could just remove the "warning as error" switch , but then again anyone wanting this could just add it ..

@John (should be Johan)
Google said this one will do the trick

Quote:
-Werror
will treat all warnings as errors

Maybe you want this one also

Quote:
-pedantic

Well ... have a look here (someone wrote a "book") :-)

http://gcc.gnu.org/onlinedocs/gc...

/Bingo

Last Edited: Wed. Feb 9, 2005 - 07:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Maybe you want this one also
Quote:
-pedantic


pedantic is my middle name.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@john
I actually meant Johan (just didnt write that) ....

/Bingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bingo600 wrote:

I sometimes do declare variables that i don't use until i get a loong way down in a routine. or do the

uint8_t  i,j,k,l,m;

just to have som locals for loopcounts etc.

Then perhaps you should start using some C99 features, such as declaring variables anywhere in the function (not just at top). Such as:

#include 
#include 
#include 
void foo(void)
{
    for(uint8_t i = 0; i < bignum; i++)
    {
        // Process....
        // Note that variable 'i' only has scope in this block.
    }

    uint8_t old_sreg = SREG;
    cli();
    // Critical section here.
    SREG = old_sreg;

    // More stuff....
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@EW ...
He..He

Thats neat ...

I wonder if this old dog can accept/(cope with) those new tricks :-)

But nice hint

I wonder if GCC would produce less code in the "for" block , or if the optimizer would allready see that the i is "out of scope" when we come further down , and automaticly use the storage (prob a register) for other purposes.

/Bingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, there's potential for GCC to do that. But, obviously, it's depends on the code involved, optimizer settings, etc.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

EW wrote:

...
    for(uint8_t i = 0; i < bignum; i++)
    {
        // Process....
        // Note that variable 'i' only has scope in this block.
    }
...

Are you sure about that comment?
This way of declaring variables has been possible in various versions of C for a long time. I *think* this is one of those places where the C standard was written in a fuzzy way, so it might be OK for a compiler to allow it and still be compliant to the standard.

There was a lot of talk about whether the variable should be in scope after the for loop. After much ado, the de facto "standard" said that the scope continued after the for loop. And since there are a lot of code written that way, it might be hard to change that. So it would be strange if C99 changed it so the scope ends with the for loop. (Language standard comittes are usualy paranoid about changes that break old source code.)

Why should the scope continue?
IIRC the (old) C-standard says that:

for(A; B; C) {
  D;
}

is equivalent to

A;
while(B) {
  D;
  C;
}

Note that A is outside the while loop, so if a variable is defined in A, it should stay after the loop.

With all that said, *I* personally would like it better if it was like you said.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Henrik G wrote:

Are you sure about that comment?
This way of declaring variables has been possible in various versions of C for a long time. I *think* this is one of those places where the C standard was written in a fuzzy way, so it might be OK for a compiler to allow it and still be compliant to the standard.

Personally, I'm not a Language Lawyer. You're best bet would be to ask one on the comp.lang.c newsgroup.

I'll be interested to know what you find out.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's still my middle name!

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yep I agree with the "100% compile" philosophy. It's much better to be safe than sorry.

I sometimes add unesseary brackets or use multiple lines for code that dosn't need it - just be be clear. I can't count how many times i've gone over my code, removed what I thought was useless code and then scratched my head later when nothing would work. Like it was once said: "don't be clever, be clear."

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks all, I was being sarcastic about warnings in the originl post. And I too strive to eliminate all warnings or be darn sure I understand their meaning before releasing any code. I have too often heard an engineer say something to the effect of "oh, it's just a warning" How many folks use PCLint? was it worth the cost? -Bryan

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

-Wall does a pretty good job.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry for picking up this old thread, but my question is tightly related to discussed above:

JohanEkdahl wrote:
The original question was why
PORTB = ~0xff; 

generates a warning "large integer implicitly truncated to unsigned type". As Dean (abcminiuser) pointed out it's because the complement operator (~) procudes a 16-bit integer value. The warning then occurs when we try to assign such a value to PORTB which is 8 bits.

One user in one russian forum asked almost the same question:
unsigned char gg;
gg = ~0x76;
gg = ~0x86;

produces the same warning in IAR. Interesting point is that warning is generated only for the last line. I tried to compile this test in avr-gcc and got the same result - warning "large integer implicitly truncated to unsigned type" issued only on the last line. As I understand integer promotions rules and as JohanEkdahl explained above, compiler should issue 2 warnings, but he doesn't do it in case of first equation. Why? I tried to "unwind" those expressions and got even more confusing results:

    uint8_t i;
    i = 0xFF79; //~ 0x86;  - causes warning, as expected
    i = 0xFF89; //~ 0x76;  - causes warning, as expected
    i = (int)0xFF79; //~ 0x86;  - causes warning, as expected
    i = (int)0xFF89; //~ 0x76;  - no warnings, why?

As both avr-gcc and IAR shows the same behavior, there must be some explanation in C standart I can't find.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

innocent_bystander wrote:
Sorry for picking up this old thread, but my question is tightly related to discussed above:
JohanEkdahl wrote:
The original question was why
PORTB = ~0xff; 

generates a warning "large integer implicitly truncated to unsigned type". As Dean (abcminiuser) pointed out it's because the complement operator (~) procudes a 16-bit integer value. The warning then occurs when we try to assign such a value to PORTB which is 8 bits.

One user in one russian forum asked almost the same question:
unsigned char gg;
gg = ~0x76;
gg = ~0x86;

produces the same warning in IAR. Interesting point is that warning is generated only for the last line. I tried to compile this test in avr-gcc and got the same result - warning "large integer implicitly truncated to unsigned type" issued only on the last line. As I understand integer promotions rules and as JohanEkdahl explained above, compiler should issue 2 warnings, but he doesn't do it in case of first equation. Why?

Perhaps because converting (signed int) 0xFF89 to
(unsigned char) 0x89 doesn't change the high order bit.
I've never seen that warning, ever.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skeeve wrote:
Perhaps because converting (signed int) 0xFF89 to (unsigned char) 0x89 doesn't change the high order bit.
Yes, but i is unsigned, so sign of resulting value changed from negative to positive. That's why we get warning in 3 cases.
And, than, what's the diffence between

    i = 0xFF89; //~ 0x76;  - causes warning, as expected 
    i = (int)0xFF89; //~ 0x76;  - no warnings, why?

in both cases constant 0xFF89 (without type modifiers like U, L etc) is (signed) int. Why explicit casting to the same type as it is causes warning suppres?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

innocent_bystander wrote:
skeeve wrote:
Perhaps because converting (signed int) 0xFF89 to (unsigned char) 0x89 doesn't change the high order bit.
Yes, but i is unsigned, so sign of resulting value changed from negative to positive. That's why we get warning in 3 cases.
And, than, what's the diffence between

    i = 0xFF89; //~ 0x76;  - causes warning, as expected 
    i = (int)0xFF89; //~ 0x76;  - no warnings, why?

in both cases constant 0xFF89 (without type modifiers like U, L etc) is (signed) int. Why explicit casting to the same type as it is causes warning suppres?

In the case of warnings, the answer never lies in the C standard.
The C standard does not require any warnings.
We are trying to read the minds of the gods.
As a rule, a compiler issues a warning when
you have done something that is allowed,
but the compiler suspects might not be what you intended.
Here is my attempt at mid-reading:
Both assignments do exactly the same thing.
The explicit coercion is a no-op.
The difference must be in what the compiler infers you intend.
In both assignments,
the FF is redundant and is evidence that you didn't mean what you wrote.
The compiler might treat the coercion in the second assignment
as evidence that you know what you are doing.

Were I in charge of issuing warnings,
I might be inclined to issue a warning whenever someone coerced
an expression to signed int and assigned it to unsigned char.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

innocent_bystander wrote:
Sorry for picking up this old thread, but my question is tightly related to discussed above:
JohanEkdahl wrote:
The original question was why
PORTB = ~0xff; 

generates a warning "large integer implicitly truncated to unsigned type". As Dean (abcminiuser) pointed out it's because the complement operator (~) procudes a 16-bit integer value. The warning then occurs when we try to assign such a value to PORTB which is 8 bits.

One user in one russian forum asked almost the same question:
unsigned char gg;
gg = ~0x76;
gg = ~0x86;

produces the same warning in IAR. Interesting point is that warning is generated only for the last line.

Both expressions are signed ints,
but only the second conversion changes the high bit.
Quote:
I tried to compile this test in avr-gcc and got the same result - warning "large integer implicitly truncated to unsigned type" issued only on the last line. As I understand integer promotions rules and as JohanEkdahl explained above, compiler should issue 2 warnings, but he doesn't do it in case of first equation. Why? I tried to "unwind" those expressions and got even more confusing results:
    uint8_t i;
    i = 0xFF79; //~ 0x86;  - causes warning, as expected
    i = 0xFF89; //~ 0x76;  - causes warning, as expected
    i = (int)0xFF79; //~ 0x86;  - causes warning, as expected
    i = (int)0xFF89; //~ 0x76;  - no warnings, why?

As both avr-gcc and IAR shows the same behavior, there must be some explanation in C standart I can't find.

Contrary to what I wrote earlier,
0xFF79 and 0xFF89 are unsigned ints.
Their implicit conversions remove nonzero bits.
The latter two implicit conversions are from signed int.
The last one does not change the high bit.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

innocent_bystander wrote:
Sorry for picking up this old thread, but my question is tightly related to discussed above:
JohanEkdahl wrote:
The original question was why
PORTB = ~0xff; 

generates a warning "large integer implicitly truncated to unsigned type". As Dean (abcminiuser) pointed out it's because the complement operator (~) procudes a 16-bit integer value. The warning then occurs when we try to assign such a value to PORTB which is 8 bits.

One user in one russian forum asked almost the same question:
unsigned char gg;
gg = ~0x76;
gg = ~0x86;

produces the same warning in IAR. Interesting point is that warning is generated only for the last line.

Both expressions are signed ints,
but only the second conversion changes the high bit.
Quote:
I tried to compile this test in avr-gcc and got the same result - warning "large integer implicitly truncated to unsigned type" issued only on the last line. As I understand integer promotions rules and as JohanEkdahl explained above, compiler should issue 2 warnings, but he doesn't do it in case of first equation. Why? I tried to "unwind" those expressions and got even more confusing results:
    uint8_t i;
    i = 0xFF79; //~ 0x86;  - causes warning, as expected
    i = 0xFF89; //~ 0x76;  - causes warning, as expected
    i = (int)0xFF79; //~ 0x86;  - causes warning, as expected
    i = (int)0xFF89; //~ 0x76;  - no warnings, why?

As both avr-gcc and IAR shows the same behavior, there must be some explanation in C standart I can't find.

Contrary to what I wrote earlier,
0xFF79 and 0xFF89 are unsigned ints.
Their implicit conversions remove nonzero bits.
The latter two implicit conversions are from signed int.
The last one does not change the high bit.

Iluvatar is the better part of Valar.