CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Shift operation don't work

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Mortenc



Joined: 22 Feb 2007
Posts: 55

View user's profile Send private message

Shift operation don't work
PostPosted: Wed Sep 30, 2015 10:29 am     Reply with quote

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: 9197
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Sep 30, 2015 10:41 am     Reply with quote

What is the CCS default type for variables ?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Sep 30, 2015 12:11 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Sep 30, 2015 1:13 pm     Reply with quote

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: 19433

View user's profile Send private message

PostPosted: Wed Sep 30, 2015 2:18 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Sep 30, 2015 2:52 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Sep 30, 2015 3:35 pm     Reply with quote

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
Code:
(level&32)>>C35)

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

View user's profile Send private message

PostPosted: Wed Sep 30, 2015 11:24 pm     Reply with quote

Thanks for your explanations.

I will try to make with your suggested macro.
Ttelmah



Joined: 11 Mar 2010
Posts: 19433

View user's profile Send private message

PostPosted: Thu Oct 01, 2015 1:32 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 01, 2015 1:57 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 01, 2015 2:33 am     Reply with quote

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: 19433

View user's profile Send private message

PostPosted: Thu Oct 01, 2015 3:45 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 01, 2015 4:10 am     Reply with quote

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: 19433

View user's profile Send private message

PostPosted: Thu Oct 01, 2015 8:17 am     Reply with quote

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!. Smile
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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