CRC16 CCITT code - how to adapt manufacturer sample source - c

I try to create a code that would read data from RFID reader module. In order to do this I need to do CRC16 CCITT calculation.
I have found C source code for the CRC16 checksum calculation in the reader manufacturer application technical datasheet http://www.card-sys.com/manuals/framer_eng.pdf
Unfortunately this is just a part of code not a full working example.
When the RFID reader is put in automatic mode, it automatically sends 11 bytes every time it reads a tag. CRC - this value is calculated using all of the bytes except the last two bytes which are the CRCH (CRC high byte) and CRCL (CRC low byte).
When I read RFID tag from a reader I got 11 bytes transferred... i.e. (hex) 01 0B 03 01 06 87 DB C7 FF E5 68. Last two bytes E5 68 are the CRC16 checksum for the message. In order to confirm the data is OK I need to calculate the same CRC16 against 01 0B 03 01 06 87 DB C7 FF at the destination point.
I tried putting everything together in one piece, but I do not have much experience with C programing and my code does not work.
Here is the source code:
#include <stdio.h>
#include <stdlib.h>
// CRC16 from Netronix datasheet
void CRC16(unsigned char * Data, unsigned short * CRC, unsigned char Bytes)
{
int i, byte;
unsigned short C;
*CRC = 0;
for (byte = 1; byte <= Bytes; byte ++, Data ++)
{
C = ((*CRC >> 8) ^ *Data) << 8;
for (i = 0; i < 8; i ++)
{
if (C & 0x8000)
C = (C << 1) ^ 0x1021;
else
C = C << 1;
}
*CRC = C ^ (*CRC << 8);
}
}
int main(void)
{
puts("Test...");
unsigned char * Data16="10ac0501ff";
unsigned short * CRC=0;
unsigned char Bytes16=4;
CRC16(Data16,CRC,Bytes16);
puts(CRC);
return EXIT_SUCCESS;
}
What I would like to do is learn how to use manufacturer code in working example - means how to get crc16 calculated.
Could you please help me with this? Thanks.

Using your source code I created the following program.
#include <stdio.h>
#include <stdlib.h>
// CRC16 from Netronix datasheet
void CRC16(unsigned char * Data, unsigned short * CRC, unsigned char Bytes)
{
int i, byte;
unsigned short C;
*CRC = 0;
for (byte = 1; byte <= Bytes; byte++, Data++)
{
C = ((*CRC >> 8) ^ *Data) << 8;
for (i = 0; i < 8; i++)
{
if (C & 0x8000)
C = (C << 1) ^ 0x1021;
else
C = C << 1;
}
*CRC = C ^ (*CRC << 8);
}
}
int main(void)
{
// When I read RFID tag from a reader I got 11 bytes transferred... i.e.
// (hex)01 0B 03 01 06 87 DB C7 FF E5 68.
// Last two bytes E5 68 are crc16.
// In order to confirm the data is OK I need to calculate the same crc16
// against 01 0B 03 01 06 87 DB C7 FF at the destination point.
unsigned char Data16[] = { 0x01, 0x0B, 0x03, 0x01, 0x06, 0x87, 0xDB, 0xC7, 0xFF };
unsigned short CRC = 0;
unsigned char Bytes16 = 9;
CRC16(Data16, &CRC, Bytes16);
printf(" CRC calculated is %x\n", CRC);
return EXIT_SUCCESS;
}
The output is CRC calculated is e568.
There are a couple of changes I made.
First is the data I used which is from your comment on the RFID tag reader output.
When I read RFID tag from a reader I got 11 bytes transferred... i.e.
(hex) 01 0B 03 01 06 87 DB C7 FF E5 68. Last two bytes E5 68 are
crc16. In order to confirm the data is OK I need to calculate the same
crc16 against 01 0B 03 01 06 87 DB C7 FF at the destination point. You
are probably right about the Data16[]... I will change this later
today and let you know what current status is. Thanks for helping :)
I used a length of the data that excludes the checksum. So the length in the frame data is 0x0B or 11 and since the checksum is 2 bytes, I used 11 - 2 or 9 for the length.
Finally I changed the definition of the variable CRC to unsigned short CRC = 0; and when calling the CRC function, I used the address of operator as in CRC16(Data16, &CRC, Bytes16);.
Frame format for serial transmission
From the documentation you referenced there are two types of frames or messages whose formats are as follows:
Command frame:
module address (1 byte) unique address of each module in network
frame length (1 byte) full length of frame (includes 2 byte checksum)
command (1 byte) command code which is an even value
parameters (variable length) optional parameters depending on command
CRCH (1 byte) upper byte of the CRC16
CRCL (1 byte) lower byte of the CRC16
Answer frame:
module address (1 byte) unique address of each module in network
frame length (1 byte) full length of frame (includes 2 byte checksum)
answer(1 byte) answer code which is an odd value
parameters (variable length) optional parameters depending on command
operation code (1 byte) command execution status
CRCH (1 byte) upper byte of the CRC16
CRCL (1 byte) lower byte of the CRC16

Related

Simple serial comm. & Calculating CRC16 using C

I have a sensor in which I wish to get some data from. I want to ask it the date or ask it for data.
The sensor uses RS-232; 9600 8N1 to communicate.
The communication packet is composed with a header, payload and CRC. The manual provides the header and payload for whatever you want to do. Each communication packet is composed as follows:
<SOH> header <STX> payload <ETB> CRC16 <ETX>
<SOH>: 0x01
<STX>: 0x02
<ETB>: 0x17
<ETX>: 0X03
The manual gives an example if you want to ask for the date, it tells you the header is 0x31 and the payload is 0x41.
Thus the command to send the sensor is: \x01\x31\x02\x41\x17\CRC16\x03
Now as an example, the manual also calculates the CRC16 for you, and is A0D5 in ASCII. CRC16 needs to be transmitted little endian.
So the full command is now:
\x01\x31\x02\x41\x17\x44\x35\x41\x30\x03
The manual doesn't provide any other CRC16 calculations, and it expects the user to do it which is fine :)
From the manual: Each packet is validated by a 16-bit CRC transferred in hexademiical ASCII coded (four chars). CRC is calculated from the header+payload concatenated
WORD CRC16_Compute( BYTE *pBuffer, WORD length )
{
BYTE i;
BOOL bs;
WORD crc=0;
while( length-- )
{
crc ^= *pBuffer++;
for( i = 0; i < 8; i++ )
{
bs = crc & 1;
crc >>= 1;
if( bs )
{
crc ^= 0xA001;
}
}
}
return crc;
}
That is the CRC calculator in C, I am not too savvy with but this code snippet is all they provide and no context.
In ASCII, they are using 1+A (0x31+0x41) to get 2 byte, A0D5. Could someone explain to me what the CRC code is doing, thanks!
#include <stdio.h>
typedef unsigned char BYTE;
typedef unsigned int BOOL;
typedef unsigned int WORD;
WORD CRC16_Compute( BYTE *pBuffer, WORD length )
{
BYTE i;
BOOL bs;
WORD crc=0;
while( length-- )
{
crc ^= *pBuffer++;
for( i = 0; i < 8; i++ )
{
bs = crc & 1;
crc >>= 1;
if( bs )
{
crc ^= 0xA001;
}
}
}
return crc;
}
int main ( void )
{
unsigned char data[2];
unsigned char sdata[9];
unsigned int x;
unsigned int z;
unsigned int i;
data[0]=0x31;
data[1]=0x41;
x = CRC16_Compute(data,2);
x&=0xFFFF;
printf("0x%X\n",x);
z=0;
sdata[z++]=0x01;
sdata[z++]=data[0];
sdata[z++]=0x02;
sdata[z++]=data[1];
sdata[z++]=0x17;
sdata[z ]=((x>> 4)&0xF)+0x30; if(sdata[4]>0x39) sdata[4]+=7; z++;
sdata[z ]=((x>> 0)&0xF)+0x30; if(sdata[5]>0x39) sdata[5]+=7; z++;
sdata[z ]=((x>>12)&0xF)+0x30; if(sdata[6]>0x39) sdata[6]+=7; z++;
sdata[z ]=((x>> 8)&0xF)+0x30; if(sdata[7]>0x39) sdata[7]+=7; z++;
sdata[z++]=0x03;
for(i=0;i<z;i++) printf("%02X ",sdata[i]); printf("\n");
return(0);
}
Run it
gcc so.c -o so
./so
0xA0D5
01 31 02 41 17 44 35 41 30 03
How about that the right answer....
Everything you need to know is in your question, just do what it says. A few minutes of crudely putting it together.
CRC is calculated from the header+payload concatenated
data[0]=0x31;
data[1]=0x41;
That is header and payload and it gives the right answer based on the CRC code provided.
Then you build the packet with the other items. If you google ASCII table you can see the values for 'D' 'A' '0' '5' and can figure out how to get from 0xD to 0x44 and 0xA to 0x41 but first look at 0x0 to 0x30 and 0x5 to 0x35, 0-9 is easy but 0x0A gives 0x3A but needs to be 0x41, so you adjust.
So the code works as described based on the comments as described, I don't know this sensor, seems goofy the way they did it but good for them for providing an example and the details on the crc16 as there are multiple standard variations including the initial value, so again good for them for saving tons of time trying to figure it out...

Modbus functional code 1 & crc check for PIC microcontoller

I need help in calculating modbus CRC check for function code 1. I.e read coil register. I have sample code for CRC check for function code 3 i.e holding register for analog input.
# Read Coil Status (FC=01)
## Request
This command is requesting the ON/OFF status of discrete coils # 20 to 56
from the slave device with address 17.
11 01 0013 0025 0E84
11: The Slave Address (17 = 11 hex)
01: The Function Code (read Coil Status)
0013: The Data Address of the first coil to read. (Coil 20 - 1 = 19 = 13 hex)
0025: The total number of coils requested. (coils 20 to 56 = 37 = 25 hex)
0E84: The CRC (cyclic redundancy check) for error checking.
Response
11 01 05 CD6BB20E1B 45E6
11: The Slave Address (17 = 11 hex)
01: The Function Code (read Coil Status)
05: The number of data bytes to follow (37 Coils / 8 bits per byte = 5 bytes)
CD: Coils 27 - 20 (1100 1101)
6B: Coils 35 - 28 (0110 1011)
B2: Coils 43 - 36 (1011 0010)
0E: Coils 51 - 44 (0000 1110)
1B: 3 space holders & Coils 56 - 52 (0001 1011)
45E6: The CRC (cyclic redundancy check).
Read Holding Registers (FC=03)
Request
This command is requesting the content of analog output holding registers # 40108 to
40110 from the slave device with address 17.
11 03 006B 0003 7687
11: The Slave Address (17 = 11 hex)
03: The Function Code (read Analog Output Holding Registers)
006B: The Data Address of the first register requested. (40108-40001 = 107 = 6B hex)
0003: The total number of registers requested. (read 3 registers 40108 to 40110)
7687: The CRC (cyclic redundancy check) for error checking.
Response
11 03 06 AE41 5652 4340 49AD
11: The Slave Address (17 = 11 hex)
03: The Function Code (read Analog Output Holding Registers)
06: The number of data bytes to follow (3 registers x 2 bytes each = 6 bytes)
AE41: The contents of register 40108
5652: The contents of register 40109
4340: The contents of register 40110
49AD: The CRC (cyclic redundancy check).
I am no issue for getting response for FC3. because i am sending properly the 2 byte address , but i dont know how can i send single byte and modify crc function for FC1 ->read coil register
Discription of read coil register
unsigned int crc_fn(unsigned char *dpacket,unsigned int len) { // CRC Function(Error calcualtion)
unsigned int crc = 0xffff,poly = 0xa001;
unsigned int i=0;
for(i=0; i<len; i++) {
crc^= dpacket[i];
for(j=0; j<8; j++) {
if(crc & 0x01) {
crc >>= 1;
crc ^= poly;
} else
crc >>= 1;
}
}
return (crc);
}
CRC is normally appended to a message most significant byte first. You need to swap two lines of code, sending the high order byte of the 16 bit crc before the low order byte. Try this change:
Serial_1_Send_byte((unsigned char)(crc1>>8));
Serial_1_Send_byte((unsigned char)crc1);

How is the carry flag being set in this assembly code?

Given the following assembly code for a 16-bit PRNG function,
$80/8111 E2 20 SEP #$20 ; set 8-bit mode accumulator
$80/8113 AD E5 05 LDA $05E5 ; load low byte of last random number
$80/8116 8D 02 42 STA $4202
$80/8119 A9 05 LDA #$05 ; multiply it by 5
$80/811B 8D 03 42 STA $4203
$80/811E EA NOP
$80/811F C2 20 REP #$20 ; set 16-bit mode accumulator
$80/8121 AD 16 42 LDA $4216 ; load the resultant product
$80/8124 48 PHA ; push it onto the stack
$80/8125 E2 20 SEP #$20 ; 8-bit
$80/8127 AD E6 05 LDA $05E6 ; load high byte of last random number
$80/812A 8D 02 42 STA $4202
$80/812D A9 05 LDA #$05 ; multiply by 5
$80/812F 8D 03 42 STA $4203
$80/8132 EB XBA ; exchange high and low bytes of accumulator
$80/8133 EA NOP
$80/8134 AD 16 42 LDA $4216 ; load low byte of product
$80/8137 38 SEC
$80/8138 63 02 ADC $02,s ; add to it the high byte of the original product
$80/813A 83 02 STA $02,s ; save it to the high byte of the original product
$80/813C C2 20 REP #$20 ; 16-bit
$80/813E 68 PLA ; pull it from the stack
$80/813F 69 11 00 ADC #$0011 ; add 11
$80/8142 8D E5 05 STA $05E5 ; save as new random number
$80/8145 6B RTL
a user by the name of #sagara translated the code to C:
#define LOW(exp) ((exp) & 0x00FF)
#define HIGH(exp) (((exp) & 0xFF00) >> 8)
uint16_t prng(uint16_t v) {
uint16_t low = LOW(v);
uint16_t high = HIGH(v);
uint16_t mul_low = low * 5;
uint16_t mul_high = high * 5;
// need to check for overflow, since final addition is adc as well
uint16_t v1 = LOW(mul_high) + HIGH(mul_low) + 1;
uint8_t carry = HIGH(v1) ? 1 : 0;
uint16_t v2 = (LOW(v1) << 8) + LOW(mul_low);
return (v2 + 0x11 + carry);
}
I'm confused by two things.
In this line...
uint16_t v1 = LOW(mul_high) + HIGH(mul_low) + 1;
Why is there a + 1? I think it's because of the ADC operation, but how can we be sure that the carry flag is set to 1? What previous operation would guarantee this? The XBC? I read a few posts such as Assembly ADC (Add with carry) to C++ and Overflow and Carry flags on Z80 but it's not clear to me because the instruction set appears to be different I'm not familiar with 65C816 assembly. (This is from a popular 1994 SNES game whose NA release anniversary recently passed; free upvote to the correct guess :-)
In the next line...
uint8_t carry = HIGH(v1) ? 1 : 0;
Why would it work this way? I read this as, "Set the carry flag if and only if the high byte is non-zero." But wouldn't the indication of an overflow be only if the high byte is zero? (I'm probably misinterpreting what the line is doing.)
Thanks in advance for any insights.
but how can we be sure that the carry flag is set to 1? What previous operation would guarantee this?
$80/8137 38 SEC ; SEt Carry flag
uint8_t carry = HIGH(v1) ? 1 : 0;
Why would it work this way? I read this as, "Set the carry flag if and only if the high byte is non-zero." But wouldn't the indication of an overflow be only if the high byte is zero?
The addition ADC #$0011 is using the carry from ADC $02,s. When ADC $02,s is performed, the accumulator is set to 8-bit (because of SEP #$20), so the carry flag will be set if the result of ADC $02,s would've exceeded 8 bits (i.e. if you would've got something >= $100 in 16-bit mode).
In the C version you've got a 16-bit variable (v1) to hold the result, so your carry will be in bit 8 of v1, which you can test with HIGH(v1) == 1, or simply HIGH(v1) since it will either be 1 or 0.
1) The line
$80/8137 38 SEC
is explicity setting the carry just before an ADC add-with-carry instruction, that's why the +1 in the C code.
2) The processor has an 8-bit accumulator, and the addition will overflow to the carry, ready for the next ADC instruction. However, the C code is using a 16-bit variable v1, and the carry remains in the upper 8 bits. Hence the test of those upper 8 bits to extract the so-called "carry".

image data of bmp in C

How to convert a monochrome bmp image file (in my case 16*16 pixels) into binary format? This code reads the bitmap information. I have to store the pixel information into an array & it's not stored properly. I have shared the code
#pragma pack(push, 1)
typedef struct BitMap
{
short Signature;
long Reserved1;
long Reserved2;
long DataOffSet;
long Size;
long Width;
long Height;
short Planes;
short BitsPerPixel;
long Compression;
long SizeImage;
long XPixelsPreMeter;
long YPixelsPreMeter;
long ColorsUsed;
long ColorsImportant;
long data[16];
}BitMap;
#pragma pack(pop)
reading image file:
struct BitMap source_info;
struct Pix source_pix;
FILE *fp;
FILE *Dfp;
Dfp=fopen("filename.bin","wb")
if(!(fp=fopen("filename.bmp","rb")))
{
printf(" can not open file");
exit(-1);
}
fread(&source_info, sizeof(source_info),1,fp);
printf("%d\n",source_info.DataOffSet);
printf("%d\n",source_info.Width*source_info.Height);
for(i=0;i<16;i++)
fprintf(Dfp,"%d\t",source_info.data[i]);
Observed output using hex editor is
Highlighted data i want to get stored in data array so that i can use it further in the code.
However output in filename.bin is
0 16777215 63 63 63 95 95 95
31 31 31 31 31 31 31 31
I'm new to this field. Can someone help me out where i'm going wrong?
There's actually no problem with the data.
The problem is you're using the wrong way to print them.
Try replacing your code:
printf("%d\n",source_info.DataOffSet);
printf("%d\n",source_info.Width*source_info.Height);
for(i=0;i<16;i++)
fprintf(Dfp,"%d\t",source_info.data[i]);
with this:
printf("%x\n",source_info.DataOffSet);
printf("%x\n",source_info.Width*source_info.Height);
for(i=0;i<16;i++)
fprintf(Dfp,"%x\t",source_info.data[i]);
As %d is for signed decimals while %x is for hexadecimals. See the section of The conversion specifier in the manual page of printf
EDITED:
As you've posted your new questions in the comments:
output in hex is 0x00 0xffffff 0x3f 0x3f 0x3f 0x5f 0x5f 0x5f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f Can u explain how the output is getting stored? I'm unable to get the same output – user2967899 7 mins ago
here's my edited answer.
Assumptions: your working platform is just as normal, on which size of short is 2 bytes and of long it's 4.
From definition of struct BitMap we know the field data is at its offset of 0x36. Comparing of the image we know the data shall be (in hexadecimal):
data[0]: 0000 0000
data[1]: ffff ff00
......
Then the result you got seems strange since data[1] is 0x00ffffffff instead of 0xffffff00. However that's correct. This is cause by endianess, for which please read this wiki page first: http://en.wikipedia.org/wiki/Endianness
As the hex-editor represents data in the real order of bytes, and I assume you're working with a little-endian machine (which most PC on this planet has), this order is just reversed of the real order of your data in long:
/* data in C */
unsigned long x = 305419896; /* 305419896 == 0x12345678 */
/* arithmetically the four bytes in x: */
/* 0x12 0x34 0x56 0x78 */
/* the real order to be observed in a hex-editor due to endianess: */
/* 0x78 0x56 0x34 0x12 */
/* so this holds true in C: */
unsigned char *a = &x;
assert(a[0] == 0x78);
assert(a[1] == 0x56);
assert(a[2] == 0x34);
assert(a[3] == 0x12);

Binary 0000 to FFFF using C

I am trying to program using C to write binary data to a .bin file and just iterate through to write from 0000 to FFFF. I figured I would use fopen with a 'wb' tag and then be able to write binary data but I'm unsure how to iterate from 0000 to FFFF using C. Thanks for any help.
Here's my code now:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *f = fopen("binary.bin", "wb");
unsigned long i;
//if(f == NULL) { ...error handling... }
for(i = 0x0000; i <= 0xFFFF; i++){
// Write something to the file, e.g. the 16-bit (2 byte) value of "i"
unsigned short someData = i;
fwrite(&someData, 1, 2, f);
}
fclose(f);
return 0;
//printf("Hello World\n");
getchar();
}
This will output 00 00 01 00 02 00 ...
Here's my question now. Isn't this supposed to read out 00 00 00 01 00 02...Shouldn't there be an extra '00' at the beginning?
Also, I've been trying to see how could I copy it and extend it therefore making it 0000 0000 0001 0001 etc?
[Update: I just copied the fwrite line and did it again and it solved this problem]
This is a simple example of writing some binary numbers to a file.
FILE *f = fopen("yourfile", "wb");
if(f == NULL) { ...error handling... }
for(unsigned long i = 0x0000; i <= 0xFFFF; ++i)
{
// Write something to the file, e.g. the 16-bit (2 byte) value of "i"
unsigned short someData = i;
fwrite(&someData, 1, 2, f);
}
fclose(f);
Note that the variable i here must be bigger than 16-bit so that it does not wrap around (see my comments on the other answers). The long type guarantees a size of at least 32 bit.
for (int i = 0x0000; i <= 0xffff; ++i)
To loop from 0 to 0xffff, both inclusive, you do:
for (i=0; i <= 0xffff; ++i)
Now, the first interesting question is, what should be the type of i? In C, an unsigned int is guaranteed to hold values in the range [0, 0xffff], which means that i <= 0xffff will always be true for unsigned int i; if UINT_MAX is 0xffff. so i can't be a type of size smaller or equal to unsigned int. long or unsigned long is the smallest type guaranteed to be able to store 0xffff + 1 portably. So, we need i to be of unsigned long or long type. In C99, you can make things easier by including stdint.h and then using uint32_t type.
The second interesting question is, what do you want to write? Is your file's layout going to be:
00 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07
...
FF F8 FF F9 FF FA FF FB FF FC FF FD FF FE FF FF
or do you want to write values to a file using your favorite data type above and then be able to read them back again quickly? For example, if int is 32 bits, and your system is little-endian, writing those values will give you a file such as:
00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 ...
If you want the first, you have to make sure you write two bytes per number, in the correct order, and that endian-ness of your OS doesn't affect the output. The easiest way to do so is probably something like this:
for (i=0; i <= 0xff; ++i) {
unsigned char values[2];
values[0] = (i & 0xff00) >> 8;
values[1] = i & 0xff;
fwrite(values, 1, 2, fp);
}
If you want the second, your life is easier, particularly if you don't care about endian-ness:
for (i=0; i <= 0xff; ++i) {
fwrite(&i, sizeof i, 1, fp);
}
will write your values so you can read them back on the same system with the same kind of variable.
for (i = 0x0000; i <= 0xFFFF; ++i)
To control the Endianess of your output, you will have to write the bytes (octets) yourself:
for (unsigned int i = 0; // Same as 0x0000
i <= 0xFFFF;
++i)
{
unsigned char c;
c = i / 256; // In Big Endian, output the Most Significant Byte (MSB) first.
fputc(/*...*/);
c = i % 256;
fputc(/*...*/);
}
This is a preferred method when the file must be Big Endian. This will ensure the byte ordering regardless of the processor's endianess. This can be adjusted to output in Little Endican as well.
Alternate method for portably writing bytes in big endian style: check out htons and htonl (and their inverses).
These convert from whatever format your machine uses (Intel chips are little endian, as several people have pointed out) into "Network" order (big endian). htons does this in 16-bit words; htonl in 32-bit words. As an added benefit, if your program is on a Big Endian machine, these compile out to no-ops. They're defined in <arpa/inet.h> or <netinet/in.h>, depending on the system.
BSD (and Linux) also provide(s) a collection of routines named things like htobe16 (host to big endian 16-bit) in <endian.h>.
These also help save the overhead of writing one byte at a time.
If you do want to extract high bytes / low bytes yourself, you probably should also use bit masking to do it. Your compiler might be smart enough to convert divide/modulo into bit masks, but if it doesn't, you'll have deplorable performance (division is slow).
{
unsigned int x = 0xdead;
unsigned char hi = (x & 0xff00) >> 8;
unsigned char lo = (x & 0x00ff);
}
{
unsigned long int x = 0xdeadbeef;
unsigned char by0 = (x & 0xff000000) >> 24;
unsigned char by1 = (x & 0x00ff0000) >> 16;
unsigned char by2 = (x & 0x0000ff00) >> 8;
unsigned char by3 = (x & 0x000000ff);
}
(It looks like gcc is smart enough to do the optimization out of the division, though… nice.)

Resources