Thread: Write Binary File

  1. #1
    carpe diem
    Join Date
    Jan 2010
    Posts
    46

    Write Binary File

    Hi,
    I have to write a .bin file with a specific format (64 words, 12 bits each word). I can create a file with a bunch of zeros and ones, but each one of those numbers ends being a byte, not a bit.
    How can I use fwrite to output a given set of numbers (eg.1300 and 29) to a file in 12-bit format?
    Any help is much appreciated!

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    So do two 12-bit numbers get written out in 3 bytes, like this?

    aaaaaaaa aaaabbbb bbbbbbbb
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Yeah, you need to use the lowest common multiple of 12 and 8 (24) to give you an even number of bytes, because fwrite will only work with whole bytes:

    Code:
    #include <stdio.h>
    #include <string.h>
    
    typedef struct {
    	int v :24;		/* 24-bits = 3 bytes */
    	#pragma pack(1)		/* make sure struct is 3 bytes */
    } twelveX2;
    
    int main() {
    	twelveX2 eg;
    	int n;
    
    	n = (666<<12) + 666;
    	memcpy(&eg,&n,3);
    
    	printf("%d\n",sizeof(eg));
    
    	return 0;
    }
    So one number occupies the top of the 3 byte int, and the other the bottom. I don't know how signedness will affect this, you will have to do further experimentation. If the numbers are always positive just use unsigned types for everything and don't worry about it. You cannot just use a typedef with
    Code:
    int val :12
    Because there is no way to prevent the compiler from padding this to the nearest byte.

    You write those directly to the file, don't place them in a string qv:
    SourceForge.net: Serialization - cpwiki

    This will work since 64 is an even number.
    Last edited by MK27; 02-22-2010 at 11:31 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #4
    carpe diem
    Join Date
    Jan 2010
    Posts
    46
    Thanks guys! It is starting to make sense now. However I just can't understand this part of the code
    Code:
    n = (666<<12) + 666;
    Could you please elaborate as to why you added 666 after the left shift?

  5. #5
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    << is a left shift. Consider a bit pattern of:

    0000 0100 0000 0000

    If we shift it left twice, it looks like:

    0001 0000 0000 0000

    If we shift that right five times, it looks:

    0000 0000 1000 000

    They don't rotate however:

    0100 << 2 does not equal 0001 it is instead 0000

    So, let's say we do this:

    (0001 1000 << 2) + 0001 1000 should give you: 0111 1000


    Quzah.
    Hope is the first step on the road to disappointment.

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by doia View Post
    Thanks guys! It is starting to make sense now. However I just can't understand this part of the code
    Code:
    n = (666<<12) + 666;
    Could you please elaborate as to why you added 666 after the left shift?
    That could be any number less than or equal to 2048, which is the highest value you can fit in an unsigned 12-bit number. When you shift bits, anything "shifted in", is zero, eg, a one byte value equal to 1:

    00000001

    Now shift this <<4:

    00010000

    Now shift that >>2:

    00000100

    So here's the same code (using two different numbers instead), and reversing the process afterward (which you would have to when reading this file). Also, I changed everything to unsigned. IF YOU NEED TO USE NEGATIVE NUMBERS SAY SO, THAT WILL BE A SIGNIFICANT COMPLICATION:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    typedef struct {
    	unsigned int v :24;		/* 24-bits = 3 bytes */
    	#pragma pack(1)		/* make sure struct is 3 bytes */
    } twelveX2;
    
    int main() {
    	twelveX2 eg;
    	unsigned int n, copy = 0, a, b;
    
    	n = (666<<12) + 444;
    	memcpy(&eg,&n,3);
    
    	/* extraction */
    	memcpy(&copy,&eg,3);
    	a = b = copy;
    	a &= ~(~0<<12);	// zero out upper bits
    	b = b>>12;	// zero out lower bits
    
    	printf("eg size: %ld bytes. lower value: %u upper value: %u\n",sizeof(eg), a, b);
    
    	return 0;
    }
    The output is:
    eg size: 3 bytes. lower value: 444 upper value: 666

    Here's how "a &= ~(~0<<12)" works:

    ~ is the "complement operator", it reverses all the bits (try google).

    So ~0 is all bits set. Shift that 12 to the left, and you have an int with the lower 12 bits unset, the upper set:
    11111111 11111111 11110000 00000000

    Now, ~ (ie, flip) that and:
    00000000 00000000 00001111 11111111
    This is the "AND" mask that we want. AND'ing a number with that will zero out anything past the lower twelve bits. That's the how we get the lower value.

    The upper value is simple, you just shift >>12.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    carpe diem
    Join Date
    Jan 2010
    Posts
    46
    I need to use negative numbers =(

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    To handle negatives, try this:

    Code:
    unsigned int convert_32bit_to_12bit( int v )
    {
        return (unsigned int)( v << 20 ) >> 20;
    }
    
    int convert_12bit_to_32bit( unsigned int v )
    {
        return (int)((unsigned int)v << 20) >> 20;
    }
    What this is doing is shifting the value bits over until they are adjacent to the sign bit, casting to unsigned to remove the 'specialness' of the sign bit, then shifting back over again. The result is a 12-bit quantity with the MSB being a sign bit (don't be fooled by the "unsigned int" return type -- we're talking about a bit pattern, not a C data type)
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  9. #9
    carpe diem
    Join Date
    Jan 2010
    Posts
    46
    Quote Originally Posted by brewbuck View Post
    To handle negatives, try this:

    Code:
    unsigned int convert_32bit_to_12bit( int v )
    {
        return (unsigned int)( v << 20 ) >> 20;
    }
    
    int convert_12bit_to_32bit( unsigned int v )
    {
        return (int)((unsigned int)v << 20) >> 20;
    }
    What this is doing is shifting the value bits over until they are adjacent to the sign bit (...)
    Wouldn't you shift only 19 bits so that it they are adjacent to the sign bit?

  10. #10
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    You own a computer right? There is only one way to find out in a situation like this

    You could always try apply your fresh knowledge of bit manipulation to write a function will take a value -1025 to 1024 (11 bits + sign) and return an unsigned int with the bits set appropriately. To do that, you'll have to understand two's complement:

    Two's complement - Wikipedia, the free encyclopedia

    Start slugging and see how far you can get.
    Last edited by MK27; 02-26-2010 at 08:55 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  11. #11
    Registered User
    Join Date
    Jan 2010
    Posts
    412
    Quote Originally Posted by MK27 View Post
    You could always try apply your fresh knowledge of bit manipulation to write a function will take a value -1025 to 1024 (11 bits + sign) and return an unsigned int with the bits set appropriately.
    Isn't a 12-bit signed number (11 bits value + 1 sign bit) -2048 to 2047?
    And for your 11-bit example, shouldn't it be -1024 to 1023?

  12. #12
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by _Mike View Post
    Isn't a 12-bit signed number (11 bits value + 1 sign bit) -2048 to 2047?
    And for your 11-bit example, shouldn't it be -1024 to 1023?
    Nope** -- err, yes to the last bit* (should have been -1024 to 1023).
    Code:
      1 1
      2 2
      3 4
      4 8
      5 16
      6 32
      7 64
      8 128
      9 256
     10 512
     11 1024
     12 SIGN
    *pun
    ** sorry yep...
    Last edited by MK27; 02-26-2010 at 10:15 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  13. #13
    Registered User
    Join Date
    Jan 2010
    Posts
    412
    Quote Originally Posted by MK27 View Post
    Code:
      1 1
      2 2
      3 4
      4 8
      5 16
      6 32
      7 64
      8 128
      9 256
     10 512
     11 1024
     12 SIGN
    And if you add the sum of all bit values 1-11 you get 2047

  14. #14
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I was just doing the dishes and this little blunder had me rushing to the keyboard in hopes no one had noticed my stupidity yet...
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  15. #15
    Registered User
    Join Date
    Jan 2010
    Posts
    412
    You actually had me quite confused there for a while. Are my calculations wrong? Am I just misunderstanding what you meant? etc..
    But then when you posted that list I realized the error was not on my side
    Last edited by _Mike; 02-26-2010 at 10:21 AM. Reason: spelling..

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Inventory records
    By jsbeckton in forum C Programming
    Replies: 23
    Last Post: 06-28-2007, 04:14 AM
  2. Basic text file encoder
    By Abda92 in forum C Programming
    Replies: 15
    Last Post: 05-22-2007, 01:19 PM
  3. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 08:39 AM
  4. Encryption program
    By zeiffelz in forum C Programming
    Replies: 1
    Last Post: 06-15-2005, 03:39 AM
  5. copying binary file
    By samc2004 in forum C Programming
    Replies: 5
    Last Post: 12-09-2003, 01:34 PM