Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Error in bitwise operations

Lafiel Takaaki
Registered User
Join date: 2 Oct 2007
Posts: 29
11-26-2007 18:42
Hallo,

I'm curently trying to dump my debug/message handling to a seperate script (so i get more space in my mainscripts).

I'm using the link_message event to communicate with this script and send a code to the debug script (as well as some flags). So i'm using the 2nd parameter of link_message, to put most of the informations in it, 3rd parameter is for custom messages and last one reserved for keys (i.e. for whispers).

Most of it seems to work fine, but i have some problems reading out some of the flags and i receive some weird and unexpected results. I've been looking for hours, for the error, but i really can't find any. And it's unlikely an SL error either, cause i ge same results in LSLEditor too.

The code looks something similar to:


//####################################
// Constants
//####################################
integer DEBUGLEVEL = 1;
integer DEBUG_FATAL = 1;
integer DEBUG_CRITICAL = 2;
integer DEBUG_WARNING = 3;
integer DEBUG_INFO = 4;
integer DEBUG_ALWAYS = 5;

integer DEBUG_RESERVED1_FLAG = 0x00004000; // Reserved
integer DEBUG_RESERVED2_FLAG = 0x00008000; // Reserved

integer DEBUG_DEBUGCHANNEL = 0x00080000; // DEBUG_CHANNEL
integer DEBUG_OWNERSAY = 0x00100000; // llOwnerSay
integer DEBUG_SAY = 0x00200000; // llSay
integer DEBUG_WHISPER = 0x00400000; // llWhisper
integer DEBUG_INSTANTMESSSAGE = 0x00800000; // llInstantMessage
integer DEBUG_MESSAGELINKED = 0x01000000; // llMessageLinked
integer DEBUG_HTTPREQUEST = 0x02000000; // slSafeHTTPRequest
//integer DEBUG_UNUSED = 0x04000000; // Unused

// Masks
integer DEBUG_MESSAGEID_MASK = 0x00003fff; // 14 Bit for Messagecodes
integer DEBUG_DEBUGLEVEL_MASK = 0x00070000; // Debug Level
integer DEBUG_MESSAGETYPE_MASK = 0x03f80000; // Message Type Mask
integer DEBUG_CHAN_NUMBER_MASK = 0xFC000000; // Chan number mask

string SERVER_URL = "http://serverurl";


default
{
state_entry() {

}

touch(integer total_number){
// Testdata on Click
integer num = 1533; // Channel
llOwnerSay((string)num);
num = (num & ~DEBUG_CHAN_NUMBER_MASK) | (25<<26);
llOwnerSay((string)num);
num = num | (DEBUG_WARNING<<16); // DEBUG_FATAL
llOwnerSay((string)num);
num = num | (DEBUG_OWNERSAY | DEBUG_WHISPER | DEBUG_DEBUGCHANNEL);
llOwnerSay((string)num);

llMessageLinked(LINK_THIS, num, "", llGetOwner());
}

link_message(integer sender_number, integer number, string message, key id) {
if(number>=1000) {
// Only process our messages
integer msg_num = number & DEBUG_MESSAGEID_MASK;
integer debuglevel = (number & DEBUG_DEBUGLEVEL_MASK) >> 16;
integer chan_num = number >> 26;
integer flags = number & DEBUG_MESSAGETYPE_MASK;
llOwnerSay("Number: "+(string)number+"\nMsg id: "+(string)msg_num+"\nDebug level: "+(string)debuglevel+"\nChannel Number: "+(string)chan_num+"\nFlags:"+flags);

string debug_msg;
if(DEBUGLEVEL!=0) {
if(debuglevel==DEBUG_FATAL) {
debug_msg = "Fatal Error: ";
} else if(debuglevel==DEBUG_CRITICAL) {
debug_msg = "Critical Error: ";
} else if(debuglevel==DEBUG_WARNING) {
debug_msg = "Warning: ";
} else if(debuglevel==DEBUG_INFO) {
debug_msg = "Debuginfo: ";
}
} else if(debuglevel==DEBUG_ALWAYS){
debug_msg = message;
}

integer index = llListFindList(msg_list, [msg_num]);
if(index!=-1){
debug_msg += llList2String(msg_list, index+1);

// Thats where the bug shows, only DEBUG_DEBUGCHANNEL, DEBUG_OWNERSAY will be displayed, whisper not
if((flags & DEBUG_DEBUGCHANNEL)==DEBUG_DEBUGCHANNEL) {
llSay(DEBUG_CHANNEL, "DBG:"+debug_msg);
}
if((flags & DEBUG_OWNERSAY)== DEBUG_OWNERSAY) {
llOwnerSay("Owner:"+debug_msg);
}
if((flags & DEBUG_SAY)==DEBUG_SAY) {
llSay(chan_num, "Say:"+debug_msg);
}
if((flags & DEBUG_WHISPER)==DEBUG_WHISPER) {
llWhisper(chan_num, "Whis:"+debug_msg);
}
if((flags & DEBUG_INSTANTMESSSAGE)==DEBUG_INSTANTMESSSAGE) {
if(id!=NULL_KEY) {
llInstantMessage(id, "IM:"+debug_msg);
}
}
if((flags & DEBUG_MESSAGELINKED)==DEBUG_MESSAGELINKED) {
llOwnerSay("DEBUG_MESSAGELINKED not implemented yet";);
}
if((flags & DEBUG_HTTPREQUEST==DEBUG_HTTPREQUEST)) {
llOwnerSay("DEBUG_HTTPREQUEST not implemented yet";);
}
}
}
}
}


When i click on the script, it executes and i get this as output:
[18:20] Debug-test: 1533
[18:20] Debug-test: 1677723133
[18:20] Debug-test: 1677919741
[18:20] Debug-test: 1683686909
[18:20] Debug-test: Number: 1683686909
Msg id: 1533
Debug level: 3
Channel Number: 25
Flags:5767168
[18:20] Debug-test: Owner:Warning: Test Message


Let it go step by step and look at the "num" as binary

00000000 00000000 00000101 11111101 = 1533 1533
01100100 00000000 00000101 11111101 = 1677723133 1533 | (25<<26)
01100100 00000011 00000101 11111101 = 1677919741 1533 | (25<<26) | (DEBUG_WARNING<<16)
01100100 01011011 00000101 11111101 = 1683686909 1533 | (25<<26) | (DEBUG_WARNING<<16) | (DEBUG_OWNERSAY | DEBUG_WHISPER | DEBUG_DEBUGCHANNEL)

So we got
01011011 but, the flags i set, was
00010000 DEBUG_OWNERSAY
01000000 DEBUG_WHISPER
00001000 DEBUG_DEBUGCHANNEL

So far so good.

But
if((flags & DEBUG_WHISPER)==DEBUG_WHISPER) {
llWhisper(chan_num, "Whis:"+debug_msg);
}

fails and is never entered. Why?! I have absolutly no expaination for this. So my next step was to display the values and their AND'ed result.

So basicly i came to:
01100100 01011011 00000101 11111101 = 1683686909 = 0x645B05FD
&
00000011 11111000 00000000 00000000 = 66584576 = 0x03f80000
--------------------------------------------------------------
00000000 01011000 00000000 00000000 = 5767168 = 0x00580000

How in gods name, can i get such a result?

Everything seems fine, but i dont get a whisper.

When i uncomment
num = (num & ~DEBUG_CHAN_NUMBER_MASK) | (25<<26);
it seems to work. But i can't imagine, how these two going to interfere each other, since the "25" is left-shifted just beyond the flags bits (and the test value also show that they haven't changed any of the flag bits by shifting.
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
11-26-2007 20:38
01100100 01011011 00000101 11111101
00000011 11111000 00000000 00000000
------------------------------------------------
00000000 01011000 00000000 00000000

that looks right to me.... what were you expecting?
'&' ignores bits not set in BOTH numbers... preserving bits that ARE set in BOTH, or to put it in other terms it shows which bits are set in a 'AND' b. '|' works similiarly to show bits set in a 'OR' b.

now this confuses me
if((flags & DEBUG_WHISPER)==DEBUG_WHISPER) {

the test should be if(flags & debug_whisper), if it doesn't have that flag, it'll be false

and what's with all the added bitshifting operators?
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -
Lafiel Takaaki
Registered User
Join date: 2 Oct 2007
Posts: 29
11-26-2007 21:10
From: Void Singer
now this confuses me
if((flags & DEBUG_WHISPER)==DEBUG_WHISPER) {

the test should be if(flags & debug_whisper), if it doesn't have that flag, it'll be false

and what's with all the added bitshifting operators?

Thats what i had before, just changed it to

if((flags & DEBUG_WHISPER)==DEBUG_WHISPER) {

after googleing a bit (which seems the the more common way).

Problem is, that according to my tests, the flag is set (see listings above), but it never enters the DEBUG_WHISPER statement.

It's funny that it works, when i comment this line
num = (num & ~DEBUG_CHAN_NUMBER_MASK) | (25<<26);

The result (without the line above) is:
00000000 01011011 00000101 11111101 = 5965309

Everything is same but the last 6 bits, but works then. With
num = (num & ~DEBUG_CHAN_NUMBER_MASK) | (25<<26);
it doesn't. I really don't understand the reason for this.

Well, i need the shiftings, to put another (small) integer value into the "number" variable.

Its encoded like this:
Bits 1-14 = Message Number (which is an index of the msg_list list which contains all the messages which shall be displayed)
Bits 15 & 16 = not used at (maybe for future use or as an identifier, so that there wont be conflict with other scripts)
Bits 17-19 = DEBUG_LEVEL (can contain values from 0-7)
Bits 20-26 = 7 Flags (which determinates how the message is shown, like in Whisper, Say, IM or llOwnerSay, Debug channel etc.)
Bits 27-32 = Channel Number (can contain values from 0-63), so the message can be send to channels other than 0.

So i need the shifting to get the chan numer again, and shifting is pretty fast way to archive this ^^

Edit:
Expected:
<Debugchannel>:Debug-test: DBG:Warning: Test Message
[21:12] Debug-test: Owner:Warning: Test Message
[21:12] Debug-test whispers: Whis:Warning: Test Message

Getting:
<Debugchannel>:Debug-test: DBG:Warning: Test Message
[21:13] Debug-test: Owner:Warning: Test Message

Whisper is not being triggered, wehen i use
num = (num & ~DEBUG_CHAN_NUMBER_MASK) | (25<<26);
(but this line doesnt change anything of the 7 bit Flags, like shown above)
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
11-26-2007 22:41
I'd imagine a few things might be factors here...

when you comment that line out you are telling it to use channel 0 for the whisper in your code... instead of channel 25...

so I will bet that if you place an llOwnersay right in front of that whisper you'll see that the test IS being entered....

but your av certainly wouldn't hear it, only another listening object, and then it has to be in range of the whisper... the bitmask is fine from what I see, it's the channel that's it's being whispered on that's an issue (25), AFAIK it fine to use off channel whispers, you just don't hear them (av can't hear on off channels by default, you have to script repeaters)

and really
num = (num & ~DEBUG_CHAN_NUMBER_MASK) | (25<<26);
should just be
num = num|(25<<26);
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -
Lafiel Takaaki
Registered User
Join date: 2 Oct 2007
Posts: 29
11-27-2007 04:48
Doh! You're right. Must have been blind, not to think of that!

To be honest, wasn't really aware, that you don't see channels other than zero in the chat window.

From: Void Singer
and really
num = (num & ~DEBUG_CHAN_NUMBER_MASK) | (25<<26);
should just be
num = num|(25<<26);

Yea, had that too, before i had that problem, just changed it to that, after reading some C/C++ guides on Bitwise operations, cause i thought there was an error in the bitwise calculation.


Bit Offtopic:
Why does += -= "shortform" operators working, but not |= and &=? It could really safe some bytes on IL code and memory usage on scripts. Would it be hard, too implement this? I don't think this would break any existing scripts, would it?
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
11-27-2007 06:33
From: Lafiel Takaaki
Doh! You're right. Must have been blind, not to think of that!

To be honest, wasn't really aware, that you don't see channels other than zero in the chat window.

sometimes it's the little things =) we stare at it so long they seem to disappear...

From: someone
Yea, had that too, before i had that problem, just changed it to that, after reading some C/C++ guides on Bitwise operations, cause i thought there was an error in the bitwise calculation.

I can tell you the reason for them using that, it has to do with user inputs, and making sure certain areas of a bitmask are cleared out... it's not a 'bad' practice (rather good in one sense) but it's better to just make sure you know what you are feeding in... and could make later debugging harder...

similiarly the reasoning behind (flags & mask)==mask)) has to do with comparing mitmasks of different lengths, and also languages that evaluate truth differently than '0=False, everything else = true'. it's done to avoid a case where one bitfield is larger than the other, so would have some flags past the end of one still showing, and thus wouldn't be equivalent but might still come up true.

both are cases of preemptively fixing something... something that shouldn't come up in lsl because of the way datatypes are implemented

From: someone
Bit Offtopic:
Why does += -= "shortform" operators working, but not |= and &=? It could really safe some bytes on IL code and memory usage on scripts. Would it be hard, too implement this? I don't think this would break any existing scripts, would it?

mostly convention I think... most languages don't implement it so neither does lsl... partly because bitwise operators are mostly used for comparison, and in more complex calculations, not so much for assignment. plus some of the other operators wouldn't come out so well... like '<<='.... isn't a bad idea though, I'd put a vote on it in Jira, if someone wrote up the suggestion ;)

PS it's your thread, I think you're allowed to derail it ;)
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -
Talarus Luan
Ancient Archaean Dragon
Join date: 18 Mar 2006
Posts: 4,831
11-28-2007 14:09
From: Void Singer
I can tell you the reason for them using that, it has to do with user inputs, and making sure certain areas of a bitmask are cleared out... it's not a 'bad' practice (rather good in one sense) but it's better to just make sure you know what you are feeding in... and could make later debugging harder...


I would tend to disagree. It is a good practice to use in a preventative sense, because it doesn't require knowledge of what goes into it. Despite whatever is there, it doesn't matter, because it is *for sure* gone now. As a result, it makes software "proofing" easier, because it sets a knowledge bar at a particular point closer to where a problem might occur. Also helps in cut and paste issues, since the code is more proven, and thus makes debugging easier, not harder.

From: someone
similiarly the reasoning behind (flags & mask)==mask)) has to do with comparing mitmasks of different lengths, and also languages that evaluate truth differently than '0=False, everything else = true'. it's done to avoid a case where one bitfield is larger than the other, so would have some flags past the end of one still showing, and thus wouldn't be equivalent but might still come up true.


More or less, it is more provable to be correct, and thus is usually taught as the "best" way to do bit flag checks. Also, (flags & some_bit) != 0 is more correct than (flags & some_bit) alone, for reasons of type sense and portability.

From: someone
both are cases of preemptively fixing something... something that shouldn't come up in lsl because of the way datatypes are implemented


I would say that they are cases of coding defensively, a la prevention, and are good examples to use for software proofing, which is about developing good programming habits and making good software as early in the design and development phase as possible. While it may not come up in LSL now, LSL is hardly static, and with the upcoming Mono changes, I would expect it to become an issue for a lot of folks. Best practices are often, well, the best for the long term.

From: someone
mostly convention I think... most languages don't implement it so neither does lsl... partly because bitwise operators are mostly used for comparison, and in more complex calculations, not so much for assignment. plus some of the other operators wouldn't come out so well... like '<<='.... isn't a bad idea though, I'd put a vote on it in Jira, if someone wrote up the suggestion ;)


Actually, most C-like languages do implement them, as well as all ANSI C implementations. LSL, though, is a significantly crippled subset of C, some of it out of necessity. Probably the most likely reason they were left out (which has annoyed me as well) is probably lack of time.

Bitwise operators are not mostly used for comparison, they are mostly used for bit manipulation. Their result is mathematical in nature, not logical. The fact that people occasionally misuse them directly as conditionals or logical results causes no end of sleepless nights in the RL software development world.

Just because a language construct lets you do something doesn't mean it is a good idea to use it. ;)