|
|
View previous topic :: View next topic |
Author |
Message |
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
Shift operation don't work |
Posted: Wed Sep 30, 2015 10:29 am |
|
|
Hi CCS forum,
I have a little problem with a simple shift operation which not work as it should.
Example:
#define C17 16
#define C35 -1
level = 50;
value = (C17 + ((level&32)>>C35));
The value should be 80 but the result is 16.
It seems to that the complier don't can handle a negative shift value.
Can this be right? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Wed Sep 30, 2015 10:41 am |
|
|
What is the CCS default type for variables ? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Sep 30, 2015 12:11 pm |
|
|
The result is undefined if the shift count is negative. This is true in the
original K&R and in C99. |
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Wed Sep 30, 2015 1:13 pm |
|
|
Both variables, level and value in unsigned INT16.
I have tried signed INT16 both with same result.
My compiler version is 4.067
If I understand you right, a shift operation with negative count is not legal for C. I'm working of doing the same bitwise AND and shift operation which I can do in an excel table and Excel understand a negative shift.
I guess is not a difficult thing to make the compiler understand that a negative shift is just the other way. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Wed Sep 30, 2015 2:18 pm |
|
|
No, extremely easy. Use the ? : construct, and something like:
#define signed_shift_right(x,y) (x<0)?y<<-x:y>>x
x will have to be signed. |
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Wed Sep 30, 2015 2:52 pm |
|
|
I think you have misunderstand me.
I mean that CCS, when they make the compiler, should take care of negative shifts.
My example is simplified. In my real program there is a lot of shift like
value = (C17 + ((level&64)>>C34) + ((level&32)>>C35) + ((level&16)<<C36) + ((level&8)<<C37) + ((level&4)<<C38) + ((level&2)<<C39) + ((level&1)<<C40));
Where C34, C35, C36, C37, C38, C39 and C40 can be both positive and negative.
I not so good at C. I don't understand 100% what your suggested define line do Ttelmah. Can you explain this line in words? |
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
|
Posted: Wed Sep 30, 2015 3:35 pm |
|
|
Mortenc wrote: | I think you have misunderstand me.
I mean that CCS, when they make the compiler, should take care of negative shifts. |
In general, the sign of the number of shifts is not known at compile time, so it would be difficult for the compiler to "take care of it". In your case perhaps the Cxx values are all known at compile time, but not in general. If the compiler really did emit code to determine at run time how to do the shift, it would add a performance burden on all other users of the compiler who are not expecting the compiler to handle negative shifts.
Quote: |
I not so good at C. I don't understand 100% what your suggested define line do Ttelmah. Can you explain this line in words? |
What he means is that you can define a macro like this:
Code: |
#define signed_shift_right(x,y) (x<0)?y<<-x:y>>x
|
Then instead of writing
you could write
Code: | signed_shift_right(C35,(level&32)) |
_________________ Robert Scott
Real-Time Specialties
Embedded Systems Consulting |
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Wed Sep 30, 2015 11:24 pm |
|
|
Thanks for your explanations.
I will try to make with your suggested macro. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Thu Oct 01, 2015 1:32 am |
|
|
The first thing to understand, is that the shift operations in C, were designed to directly link to the processor shift operations. Now these do not directly have any idea of 'signed', so a shift by a -ve number can't exist.
As PCM_Programmer points out, the language definitions are specific that the result of a -ve shift are 'undefined'. In fact it gets really interesting. On the PIC, I'd expect the signed number to be treated as unsigned, so a shift of -1 right, would actually give a shift of 255 right.
On the Intel SAR instruction, only the low five bits of the value passed are used, so a shift of -1 right, gives a shift of -31 right.
The point about the macro, is that C has a built in 'two different results' function ?:.
The function in front of the '?' is evaluated, and you get the result in front of or after the ':' depending on whether it tests as true or false.
So if x<0, you get shift left by (-x) (so a positive shift left), but if x is >=0, you get a shift right by x.
So this gives a way of defining a shift that can handle a signed number. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Thu Oct 01, 2015 1:57 am |
|
|
Mortenc, another way of thinking about it is why are there two shift operations, << and >> if either could take negative arguments? I.e. if << -2 = >> 2, why have two operations at all, instead of one generic shift operator? |
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Thu Oct 01, 2015 2:33 am |
|
|
RF_developer, I'm not sure I know what you mean, but C34 to C40 could be both negative and positive and these are not fixed, so the program must handle both negative and positive. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Thu Oct 01, 2015 3:45 am |
|
|
So, you have to write your code to do this.
The point is that C is not a super high level language. It is designed as a tool to allow people to write code at a level just above the hardware, without having to do things like multiplication, division etc., themselves. However because it is tied at a lower level to the hardware, it won't have instructions that directly do things like negative shifting. In Excel for example, this will internally have been written (probably in C....), to look at the value passed, and if the value is negative, perform a _positive_ shift in the opposite direction. This takes time to do, and for anyone wanting to code efficiently, is not what is required (since a right shift command, should imply a right shift....). Processors themselves do not support -ve shifts (try designing the hardware to do this, and you will see 'why').
C lacks a huge amount of error checking to be efficient. If you want such checking, then you have to write this yourself.
To reliably shift a -ve number (as opposed to a -ve shift), is also not defined inherently in C. The point is that the result depends first on the format the numbers are actually stored, and secondly on whether the processor uses an arithmetic shift or a logical shift. Instead the standard leaves this up to the individual compiler. In fact it also gets worse for another reason. Chips can be little endian, or big endian (the numbers are stored the opposite way round), and this then affects whether a shift right is equivalent to a *2, or /2 operation. You need to consider this when using the >> or << operators at all....
Assuming this has been accepted, to reliably handle signed shifts, requires _you_ to test and handle the situations. The reliable way is as:
Code: |
signed int32 shift_arith_right(signed int32 value, signed int8 amount)
{
int1 negative=FALSE;
if (value<0)
{
negative=TRUE;
value=-value;
}
if (amount<0)
value<<=(-amount);
else
value>>=(amount);
if (negative)
return -value;
return value;
}
|
This will be exactly the type of code used inside Excel. If the value to be shifted is -ve, it is converted to +ve and a flag set. Then if the shift amount is -ve, a left shift is instead performed using the amount converted to +ve. If the amount is positive the standard right shift is performed. Then if the flag was set to say the original number to be shifted was -ve, the sign is changed on the return.
This function will handle signed amounts and values. However you can also see how much work is involved. This is why it is not done by default, instead it is left only for people who need such features to create them.
The operation, is behaving exactly 'as it should'. It is just that you have an idea of what it 'should' do, which is not what the language standard _says_ it should do. If you want it to behave as you want, then you need to write the functions to do this. |
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Thu Oct 01, 2015 4:10 am |
|
|
Thanks for your very good explanations Ttelmah.
(I feel me a little stupid besides all clever people in this forum). |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Thu Oct 01, 2015 8:17 am |
|
|
The very second paragraph of the "C programming language", starts with the line: "C is a relatively "low level" language", and just a little further on: "Although the absence of some of these features may seem like grave deficiencies ("You mean I have to call a function to compare two character strings"), keeping the language down to modest dimensions has brought real benefits".
It is the balancing act of the language, but also means you need to be aware of the limitations. In general C does not error check anything. At some level most modern computer software is written at least in part using C. Super high level things like Excel, will have their core libraries probably written in C, and even if they are instead written using languages like C++, this itself was probably written in C!...
Have fun learning!. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|