Nesting C-Macros, CRC calculation, Eclipse Java crash - c

What I have done is awfully heavy on the preprocessor. MinGW takes a minute or 2 to compile it, but it does pass unit tests; Eclipse is struggling and pops up a Java heap low, or eventually overflow. My question is there a way to make this easier for the preprocessor? Shall I just increase my Java heap? Or is there a better way to populate a table at compile time
Here it is:
I have created a CRC look up table and decided to populate it at compile time (key word: compile time), and didn't want to hard code any numbers. So I came up with a macro to calculate CRC, only hard coding the polynomial. (perhaps slightly hard to read, but it passes unit tests)
// Define CRC polynomial
#define POLYNOMIAL (0x8005)
#define CRC_1ITERATION(crc) ( \
(((crc)&0x7FFF)<<1)^( ((crc)&0x8000)?POLYNOMIAL:0 ) )
And then propagated it to 16 iterations... a re-invocation of the macro 16 iterations deep!
// Iterate the CRC polynomial
#define CRC_2ITERATIONS(crc) CRC_1ITERATION( CRC_1ITERATION(crc) )
#define CRC_4ITERATIONS(crc) CRC_2ITERATIONS( CRC_2ITERATIONS(crc))
#define CRC_8ITERATIONS(crc) CRC_4ITERATIONS( CRC_4ITERATIONS(crc))
#define CRC_16ITERATIONS(crc) CRC_8ITERATIONS( CRC_8ITERATIONS(crc))
CRC_16ITERATIONS() is now something I can invoke to transition an input CRC to it's output 16 iterations later. I use this to populated my table. Actually, I made even more nested macros to populate the table, but to keep things simple this code is enough to make Eclipse struggle:
// Populate the table (EDIT: corrected spelling)
CRC_16ITERATIONS(0), CRC_16ITERATIONS(1), CRC_16ITERATIONS(2), CRC_16ITERATIONS(3),
CRC_16ITERATIONS(4), CRC_16ITERATIONS(5), CRC_16ITERATIONS(6), CRC_16ITERATIONS(7),
CRC_16ITERATIONS(8), CRC_16ITERATIONS(9), CRC_16ITERATIONS(10), CRC_16ITERATIONS(11),
CRC_16ITERATIONS(12), CRC_16ITERATIONS(13), CRC_16ITERATIONS(14), CRC_16ITERATIONS(15)
It worked in MinGW including passing unit tests but like I said, I think I'm blowing some sort of parenthesis or macro expansion stack in Java/Eclipse. I was hoping to scale this up to a 256 entry table but I suspect MinGW will take a half-hour to compile it.

The first eight iterations just shift the byte up eight places. You can do that in the argument, and use CRC_8ITERATIONS instead of CRC_16ITERATIONS (which by the way you misspelled it CRC_16ITERATION several times).
I.e.:
CRC_8ITERATIONS(0), CRC_8ITERATIONS(1 << 8), CRC_8ITERATIONS(2 << 8), CRC_8ITERATIONS(3 << 8),
CRC_8ITERATIONS(4 << 8), CRC_8ITERATIONS(5 << 8), CRC_8ITERATIONS(6 << 8), CRC_8ITERATIONS(7 << 8),
CRC_8ITERATIONS(8 << 8), CRC_8ITERATIONS(9 << 8), CRC_8ITERATIONS(10 << 8), CRC_8ITERATIONS(11 << 8),
CRC_8ITERATIONS(12 << 8), CRC_8ITERATIONS(13 << 8), CRC_8ITERATIONS(14 << 8), CRC_8ITERATIONS(15 << 8)
That compiles about 256 times faster for me than using CRC_16ITERATIONS.
For just that particular set, I can go faster still by initially shifting up those four zeros at the top, and using CRC_4ITERATIONS. I.e.:
CRC_4ITERATIONS(0), CRC_4ITERATIONS(1 << 12), CRC_4ITERATIONS(2 << 12), CRC_4ITERATIONS(3 << 12),
CRC_4ITERATIONS(4 << 12), CRC_4ITERATIONS(5 << 12), CRC_4ITERATIONS(6 << 12), CRC_4ITERATIONS(7 << 12),
CRC_4ITERATIONS(8 << 12), CRC_4ITERATIONS(9 << 12), CRC_4ITERATIONS(10 << 12), CRC_4ITERATIONS(11 << 12),
CRC_4ITERATIONS(12 << 12), CRC_4ITERATIONS(13 << 12), CRC_4ITERATIONS(14 << 12), CRC_4ITERATIONS(15 << 12)
That compile time was too fast for me to measure.
I can take it further, add a CRC_3ITERATIONS, and do this:
0, CRC_1ITERATION(1 << 15), CRC_2ITERATIONS(2 << 14), CRC_2ITERATIONS(3 << 14),
CRC_3ITERATIONS(4 << 13), CRC_3ITERATIONS(5 << 13), CRC_3ITERATIONS(6 << 13), CRC_3ITERATIONS(7 << 13),
CRC_4ITERATIONS(8 << 12), CRC_4ITERATIONS(9 << 12), CRC_4ITERATIONS(10 << 12), CRC_4ITERATIONS(11 << 12),
CRC_4ITERATIONS(12 << 12), CRC_4ITERATIONS(13 << 12), CRC_4ITERATIONS(14 << 12), CRC_4ITERATIONS(15 << 12)
You could use this trick on the first 128 bytes to only iterate as many times as needed with CRC_7ITERATIONS, CRC_6ITERATIONS, etc. The last 128 bytes will all need to use CRC_8ITERATIONS, which is still pretty fast. At least for me using clang llvm 3.5.
Though I prefer just running a separate program to generate a file to include that has the table in it.

Related

converting vba array that returns a long number in excel to a string ie array (67, 1)

I am fledgling VBA macro user.
I have a macro that converts a txt file into specific length fields, and it all works fine.
However, one of those fields is always a 10 digit number.
When the macro runs, this number is converted into Excel, where the last few numbers are returned as zeros as Excel doesn't like long numbers (how infuriating).
What is the best way to convert an array as below into text/string before it gets into excel?
Array(53, 1), Array (67, 1), Array(77, 1)
TrailingMinusNumbers:=True
In Excel, this would be something like =text(Array(67, 1), "general").
I've tried CStr(Array(67, 1)) & String((10),Array(67, 1)) & (Array(67, 1), As String).
Try with:
Format(Array(67, 1), String(10, "0"))
or, if decimals:
Format(Array(67, 1), "0." & String(10, "0"))

Constant time evaluation

I can't get this line to run in constant time on my micro-controller:
int zz,yy; //some binary variables
zz = (yy) ? 0 : (1 & zz);
I tried to change it to
zz = (yy) ? (0 & zz) : (1 & zz);
because & should force an evaluation of the right side even though the left side defines the result as far as I know. But it did not help.
Can anyone suggest me a solution how to make this line constant time?
It entirely depends on your compiler and its settings. Maybe (!yy) *
(1 & zz) helps?
#Quentin

Bit manipulation with or mask

Suppose I have a variable inst which holds an encoded MIPS instruction. I want to set the rt field to 0 without changing the other fields. The rt field is a 5-bit field indexed from 16-20. I first tried:
inst = inst & ~(1 << 16);
which sets the rt field to 0. Then I want to put the value of a new variable new_reg into the rt field. I tried:
inst = inst | (new_reg << 16);
Could anyone confirm whether these two lines of code are correct?
I believe the problem is with your first bitmask. The command (1 << 16) only masks the first bit, where you want to mask all of the bits from 16-20. Try:
inst = inst & ~(0x3f << 16)
Then:
inst = inst | (new_reg << 16);

Switching the bits

How can I switch the certain bits of a number? For example, given bit representation (just an example, the syntax is surely wrong!):
someNumber = 00110111
changeNumber = 11100110
Then how can I change the far right bit of someNumber with the far right bit of the changeNumber without changing the rest bits of the someNumber? So the result would be:
00110111 //someNumber
11100110 //changeNumber
________
00110110
Extract the far right bit of changeNumber:
changeNumber & 1
Remove the far right bit of someNumber:
someNumber & ~1
And OR them together:
(changeNumber & 1) | (someNumber & ~1)
To set bit n, change 1 to 2n.
One a similar line as Martin,
Test the last bit of someNumber, and use the result to select the operation to change some number ('bitwise and' or 'bitwise or')
#DEFINE SWITCH_MASK_OR 0b00000001
#DEFINE SWITCH_MASK_AND (~SWITCH_MASK_OR)
...
result = changeNumber & SWITCH_MASK_OR ? \
someNumber | SWITCH_MASK_OR : someNumber & SWITCH_MASK_AND;
I suggest the following steps:
Clear the last bit of someNumber.
someNumber &= ~1
Extract the last bit of changeNumber
int lastBit = changeNumber & 1;
Set the last bit of someNumber:
someNumber |= lastBit;
AND the changenumber with a mask of 00000001, so extracting the state of the lowest bit, all others set to 0: 00000000
AND the somenumber with a mask of 11111110, so setting the lowest bit to 0 while leaving the rest unchanged: 00110110
OR the two results together, so : 00110110

MS SQL Where Like Clause Not Returning Data

I'm trying to run this query:
SELECT
USER_KEY, CHAR_KEY, CONVERT(VARCHAR,substring(char_data, 9, 16)) as CHAR_NAME
FROM CHAR_DATA0
WHERE CONVERT(VARCHAR,substring(char_data, 9, 16)) LIKE '%BrightSide08'
Which returns me nothing. (I don't understand why)
But changing the query to
SELECT
USER_KEY, CHAR_KEY, CONVERT(VARCHAR,substring(char_data, 9, 16)) as CHAR_NAME
FROM CHAR_DATA0
WHERE CONVERT(VARCHAR,substring(char_data, 9, 16)) LIKE '%BrightSide08%'
Note that the only change is ...LIKE '%BrightSide08%'
This query now returns 1 row with the data:
21045 300434 BrightSide08
examples:
(I only need the wild card to be at the beginning because)
I want the following:
0BrightSide08
1BrightSide08
But not:
0BrightSide082
1BrightSide083
This is char_data
0x0600700701003800427269676874536964653038000000000401040024002900870000006126001E0000000000000000000000007526211E0000000000000000000000006B26021E0000000000000000000000007F26031E0000000000000000000000008C26041E0000000000000000000000009A26051E0000000000000000000000009F1F000014FE180079704700A83F0000EA47193000000000000000000000F102FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16220B00000000000000000000000000E82210000000000000000000000000006722060000000000000000000000000097221800000000000000000000000000832202000000000000000000000000000000DC055802DC055C025802D007370000000600891300009B3300004D6400004D640000BCAC050076D71F00E462362D1C1300006E600A139A58000020060000000000000000000000000000DC1701000000000000000000000000004712022B0000000000000000000000004B1203320000000000000000000001004B1204130000000000000000000001004B1205320000000000000000000001003D120600000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4712080C0000000000000000000000000106090500000000000000000000010047120A190000000000000000000001004B120B0A000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1210E09000000000000000000000202C1210E09000000000000000000000202210610000000000000000000000000000A3111000000000000000000000000004D221213000000000000000000004C004D221213000000000000000000004C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1210E09000000000000000000000202C1210E0900000000000000000000020236121800000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D221213000000000000000000004C004D221213000000000000000000004C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA221D06000000000000000000004701DA221D06000000000000000000004701FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A3D200500000000000000000000000057222105000000000000000000008201572221050000000000000000000082012F22231400000000000000000000F4012F22231400000000000000000000F401DA221D06000000000000000000004701DA221D06000000000000000000004701FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A3D200500000000000000000000000057222105000000000000000000008201572221050000000000000000000082012F22231400000000000000000000F4012F22231400000000000000000000F401FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB373011000000000000000000000000FB373011000000000000000000000000953C3202000000000000000000000000953C32020000000000000000000000001438341D0000000000000000000000001438341D000000000000000000000000B5383690000000000000000000000000B5383690000000000000000000000000FB373011000000000000000000000000FB373011000000000000000000000000953C3202000000000000000000000000953C32020000000000000000000000001438341D0000000000000000000000001438341D000000000000000000000000B5383690000000000000000000000000B5383690000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31000000C6340000000000000200000000000000040000000000000000000000000000000000000000000000000000000D0000009C00000069CF7F0000000000FFFF000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Actually, I spoke too soon in my comment. Defining an explicit length for the portion of the substring you're going after does prevent the volatility of varchar without length from interfering with your query:
DECLARE #x TABLE(y VARBINARY(MAX));
INSERT #x VALUES(
0x0600700701003800427269676874536964653038000000000401040024002900870000006126001E0000000000000000000000007526211E0000000000000000000000006B26021E0000000000000000000000007F26031E0000000000000000000000008C26041E0000000000000000000000009A26051E0000000000000000000000009F1F000014FE180079704700A83F0000EA47193000000000000000000000F102FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16220B00000000000000000000000000E82210000000000000000000000000006722060000000000000000000000000097221800000000000000000000000000832202000000000000000000000000000000DC055802DC055C025802D007370000000600891300009B3300004D6400004D640000BCAC050076D71F00E462362D1C1300006E600A139A58000020060000000000000000000000000000DC1701000000000000000000000000004712022B0000000000000000000000004B1203320000000000000000000001004B1204130000000000000000000001004B1205320000000000000000000001003D120600000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4712080C0000000000000000000000000106090500000000000000000000010047120A190000000000000000000001004B120B0A000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1210E09000000000000000000000202C1210E09000000000000000000000202210610000000000000000000000000000A3111000000000000000000000000004D221213000000000000000000004C004D221213000000000000000000004C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1210E09000000000000000000000202C1210E0900000000000000000000020236121800000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D221213000000000000000000004C004D221213000000000000000000004C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA221D06000000000000000000004701DA221D06000000000000000000004701FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A3D200500000000000000000000000057222105000000000000000000008201572221050000000000000000000082012F22231400000000000000000000F4012F22231400000000000000000000F401DA221D06000000000000000000004701DA221D06000000000000000000004701FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A3D200500000000000000000000000057222105000000000000000000008201572221050000000000000000000082012F22231400000000000000000000F4012F22231400000000000000000000F401FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB373011000000000000000000000000FB373011000000000000000000000000953C3202000000000000000000000000953C32020000000000000000000000001438341D0000000000000000000000001438341D000000000000000000000000B5383690000000000000000000000000B5383690000000000000000000000000FB373011000000000000000000000000FB373011000000000000000000000000953C3202000000000000000000000000953C32020000000000000000000000001438341D0000000000000000000000001438341D000000000000000000000000B5383690000000000000000000000000B5383690000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31000000C6340000000000000200000000000000040000000000000000000000000000000000000000000000000000000D0000009C00000069CF7F0000000000FFFF000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
);
SELECT CONVERT(VARCHAR, SUBSTRING(y, 9, 16)) FROM #x
WHERE CONVERT(VARCHAR, SUBSTRING(y, 9, 16)) LIKE '%BrightSide08';
-- 0 rows
SELECT CONVERT(VARCHAR, SUBSTRING(y, 9, 16)) FROM #x
WHERE CONVERT(VARCHAR(12), SUBSTRING(y, 9, 16)) LIKE '%BrightSide08';
-- 1 row
Now, whether you should be using 12 or something else depends on what all of the possible values might be and where they may be embedded in this specific slot in your varbinary value. If you can give some more specific examples we can help further, but in the meantime, it pays to be specific rather than wishy-washy when declaring varchar.
The most likely reason is that there is some unseen character after the 08. One way this could occur is if the field is defined as a char; it would then be padded with spaces.
One way to see if there are any such values is to append characters to delimit the value:
select '|'+char_data+'|'
. . .
You have another problem in your query. You are using varchar without a length. Bad, bad, bad. In fact, the convert doesn't seem to be needed at all. You can just do:
substring(char_data, 9, 16) LIKE '%BrightSide08'
But this is equivalent to:
left(char_data, 25) LIKE '%BrightSide08'
Or, because you are looking for values at the end of the field:
right(char_data, 12) = 'BrightSide08'

Resources