Thread: Bitfield

  1. #16
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Yes, I completely agree (and I think that has been said in full in this thread). However, there is little or no difference in efficiency between the "DIY" solution and the compiler provided solution for bitfields.

    So the benefit of using a code using and, or and shift operators over bitfields is the portability aspect - the compiler will still have to do the same and/or/shift operations in a bitfield - and it may even be slightly better at understanding what goes on.

    The code is only poor compared to individual "architecture friendly" members of a structure - e.g. in most machines, a byte, 16-bit word or 32-bit word is easy to access. But if you really insist on storing 1, 3 or 7 and 5 bits in a 16-bit word, then you will need a set of shift/and/or operations to modify the value - regardless of what the code to do that looks like.

    And neither solution provides any built-in protection in the cases regarding multiple processes/thread when accessing shared data - that is exactly the same for other operations that modify data which can be accessed from multiple threads or processes - but bitfields may be slightly more difficult to identify, as it looks like one simple access.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  2. #17
    Registered User
    Join Date
    Dec 2008
    Posts
    9
    Try this please :

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <limits.h>
    
    #define ST 1
    #define EN 2
    #define DA 8
    #define BSUM  (ST+EN+DA) 
    
    typedef struct bits /* try your desired bitfield here change macros accordingly  */
    {
     	unsigned int status : ST;
     	unsigned int enable : EN;
     	unsigned int data : DA;
    }bit_t;
    
    int main ( void )
    {
    	unsigned w ;
    	unsigned long cb = CHAR_BIT;
    
    	unsigned long s_bt  = (unsigned long) ( sizeof( bit_t ) ) * cb ;
    	unsigned long s_uc =  (unsigned long) ( sizeof( unsigned char ) ) * cb ; /* same as CHAR_BIT */
    	unsigned long s_ush =  (unsigned long) ( sizeof( unsigned short ) ) * cb ;
    	unsigned long s_ui =  (unsigned long) ( sizeof( unsigned int  ) ) * cb ;
    	unsigned long s_ul =  (unsigned long) ( sizeof( unsigned long ) ) * cb ;
    
    	printf ( "\nsize of some types in bits :\n\n" );
    	printf ( "\tbit_t size is %ld \n\tuchar size is %ld  \n\tushort size is %ld \n", s_bt , s_uc,s_ush );
    	printf ( "\tuint size is %ld \n\tulong size is %ld\n\n" , s_ui , s_ul );
    
    	for ( w = s_uc; w<= s_ul ; w *= 2 )
    	{
    		if ( w >= BSUM )
    			break;
    	}
    	if ( w == s_ul*2 )
    		w /= 2;
    	if ( (w == s_ul) && (w < BSUM) )
    	{
    		printf ( "your bitfield size is greater than size of unsigned long\n" );
    		printf ( "on this machine maybe you'd better use your bitfield as it is\n" );
    		getchar () ;
    		return EXIT_SUCCESS;
    	} else {
    		printf ( "number of bits used in bitfield struct is %ld\n", BSUM );
    		printf ( "and %ld bits are wasted due to current padding\n" ,s_bt-w);
    	}
    	getchar () ;
    	return EXIT_SUCCESS;
    }

  3. #18
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Visitor
    Try this please :
    Instead of merely providing a program and asking people to try it, describe the purpose of the program and the point you are trying to make or the question that you are trying to ask.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #19
    Registered User
    Join Date
    Dec 2008
    Posts
    9
    Please instead of coming into an ongoing discussion without previous posts , first
    read all the posts; then you may figure out what is going on. If you still can not you may
    use Display mode down the page to show you threads. Then you can understand that my
    post is a reply to matsp and it is a try to show that there are better alternatives to
    bitfields (IMO).
    Last edited by Visitor; 12-24-2008 at 03:18 PM. Reason: typo

  5. #20
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Visitor
    Please instead of coming into an ongoing into discussion without previous posts , first
    read all the posts; then you may figure out what is going on. If you still can not you may
    use Display mode down the page to show you threads.
    Please do not insult my intelligence

    Quote Originally Posted by Visitor
    Then you can understand that my
    post is a reply to matsp and it is a try to show that there are better alternatives to
    bitfields (IMO).
    Yes, but nonetheless elaborate on what you are trying to show. Note that matsp is providing a balanced case, but you have not directly addressed his points.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #21
    Registered User
    Join Date
    Dec 2008
    Posts
    9
    Quote Originally Posted by laserlight View Post
    Please do not insult my intelligence
    But you could do that ? ( assuming I wanted to ask an unrelated question in the
    middle of a thead ... )

    Code:
    Yes, but nonetheless elaborate on what you are trying to show.
    Wanted ( unluckily ) to make that interesting to build and run. Did you run it ? please tell
    me if the program has problems ... also what is the number of your wasted bits using
    the bitfield ?

    Note that matsp is providing a balanced case, but you have not directly
    addressed his points.
    Good point ; Now my suggestion to you , instead of 'proving' those "balanced cases" in
    obscure threads just put your (brilliant?) opinion on wikipedia on the appreciate page
    together with your (great?) reasoning so real experts can take a look at that ok ? I am
    interested to see their reaction ...

  7. #22
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Visitor
    But you could do that ? ( assuming I wanted to ask an unrelated question in the
    middle of a thead ... )
    Simply put, I did not see what you were trying to accomplish by posting your program (i.e., I would have to deduce your point, but such a deduction could be incorrect). It is simply good forum ettiquette to elaborate. Remember, this thread should help to answer $l4xklynx's question on the use and importance of bitfields.

    Quote Originally Posted by Visitor
    Wanted ( unluckily ) to make that interesting to build and run. Did you run it ? please tell
    me if the program has problems ... also what is the number of your wasted bits using
    the bitfield ?
    It seems fine to me. It compiled with a warning on the MinGW port of gcc 3.4.5, but the warning is benign (the %d format specifier should be used instead of %ld on line 46). My particular relevant output is "and 16 bits are wasted due to current padding".

    Quote Originally Posted by Visitor
    Good point ; Now my suggestion to you , instead of 'proving' those "balanced cases" in
    obscure threads just put your (brilliant?) opinion on wikipedia on the appreciate page
    together with your (great?) reasoning so real experts can take a look at that ok ? I am
    interested to see their reaction ...
    For one thing, I have not expressed an opinion concerning bitfields, so your suggestion does not make sense. More importantly, I suggest that you have some respect for matsp and the other members of this forum community: there are indeed experts here, and suggesting that a relevant discussion be taken elsewhere is simply rude. If you really are "interested to see their reaction", then direct the relevant Wikipedia contributors to this thread, or present the discussion to them.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #23
    Registered User
    Join Date
    Dec 2008
    Posts
    9
    Quote Originally Posted by laserlight View Post
    Simply put, I did not see what you were trying to accomplish
    by posting your program (i.e., I would have to deduce your point, but such a deduction
    could be incorrect). It is simply good forum ettiquette to elaborate. Remember, this
    thread should help to answer $l4xklynx's question on the use and importance of
    bitfields.
    Yep my very first post here showed that IMO bitfields are inefficient and I provided
    alternatives which ( IMO ) experienced people on the subject use .

    It seems fine to me. It compiled with a warning on the MinGW port of gcc 3.4.5,
    but the warning is benign (the %d format specifier should be used instead of %ld on
    line 46). My particular relevant output is "and 16 bits are wasted due to current
    padding".
    It doesn't/shouldn't hurt for %ld since an unsigned value converts to an unsigned long
    value for printf ( IMO anyway ). But by problem I meant conformance or logical or alike
    ones. Since I can compile my code too. those wasted 16 bits could have been saved using an
    unsigned short ( or whatever appreciate type for the target system is ).

    For one thing, I have not expressed an opinion concerning bitfields, so your
    suggestion does not make sense.
    But you have done that when you said matsp's post was balanced that means
    expressing opinion (IMO) though. Also matsp's him/her self didn't claim that his/her
    views were balanced; though he/she can do afterwords.

    More importantly, I suggest that you have some respect for matsp and the
    other members of this forum community: there are indeed experts here,
    Indeed I respect experts such as matsp and others here; note that by "real experts" I
    mean that I am not one on this matter so I can't answer all his points you see ? I just
    could raise the padding issue.

    and suggesting that a relevant discussion be taken elsewhere is simply rude.
    Why ? note that its not discussion going there ( in general ); One can post what he/she
    thinks is correct and missing there and others leave that unchanged ( or improve ) if
    they think that is right otherwise they might dispute that material and give their
    reasons.

    If you really are "interested to see their reaction", then direct the relevant Wikipedia
    contributors to this thread, or present the discussion to them.
    what ? Do you think that wiki is a forum or what ? Are users/contributors of Wikipedia
    responsible for material posted elsewhere ?

    I would say for the last time that in order for me to accept such technical claims one can
    expose them to a wider range of experts on the particular subject and if they confirm
    those claims I would gladly accept.

  9. #24
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Whilst I may be equally baffled as Laserlight as to what you are trying to show, I have tried your program, and got the following result. It would help if you tried to tell us what part of your code we should consider to be the "proof" and what it is proof of.
    Code:
    E:\proj\bfs\Debug>bfs
    
    size of some types in bits :
    
            bit_t size is 32
            uchar size is 8
            ushort size is 16
            uint size is 32
            ulong size is 32
    
    number of bits used in bitfield struct is 11
    and 16 bits are wasted due to current padding
    
    
    E:\proj\bfs\Debug>bfs
    
    size of some types in bits :
    
            bit_t size is 16
            uchar size is 8
            ushort size is 16
            uint size is 32
            ulong size is 32
    
    number of bits used in bitfield struct is 11
    and 0 bits are wasted due to current padding
    
    E:\proj\bfs\Debug>
    The second attempt is what you get if you change "int" to "short" in the bit_t struct. Remember that the compiler will align the entire struct to the size of the basic type, so if you ACTUALLY want the struct to be 32 bits, you should use unsigned int, if you want it to be 16 bits, use unsigned short [or some other type that has a 16-bit size - this is typically a case for using "uint32_t" or "uint16_t".

    Is this what you meant by the compiler making "inefficient" code, because to me it is "you get what you ask for" type behaviour. There is no code accessing the bitfields in this example, so there's no inefficiency in that respect.

    Edit: I have no intention to edit Wikipedia, as at least the part you quoted I have no disagrement with.

    --
    Mats
    Last edited by matsp; 12-24-2008 at 06:52 PM.
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  10. #25
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Visitor
    It doesn't/shouldn't hurt for %ld since an unsigned value converts to an unsigned long
    value for printf ( IMO anyway ).
    Actually, the warning is because the argument is an int constant (not an unsigned int) while the format specifier is for long int (not unsigned long). Nonetheless it is still harmless nitpicking by the compiler I used, for effectively the same reason that you cited.

    Quote Originally Posted by Visitor
    what ? Do you think that wiki is a forum or what ? Are users/contributors of Wikipedia
    responsible for material posted elsewhere ?
    I had the impression that you thought that Wikipedia is a forum (at least its discussion pages, and I have observed that some users do use them as forums, and rightly so, since the nature of a forum is discussion).

    Quote Originally Posted by Visitor
    Indeed I respect experts such as matsp and others here; note that by "real experts" I
    mean that I am not one on this matter so I can't answer all his points you see ? I just
    could raise the padding issue.
    Quote Originally Posted by Visitor
    I would say for the last time that in order for me to accept such technical claims one can
    expose them to a wider range of experts on the particular subject and if they confirm
    those claims I would gladly accept.
    Ah, okay, that is clearer now so I can understand where you are coming from.

    But we digress. My main point has been re-expressed by matsp:
    Quote Originally Posted by matsp
    It would help if you tried to tell us what part of your code we should consider to be the "proof" and what it is proof of.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #26
    Registered User
    Join Date
    Dec 2008
    Posts
    9
    Quote Originally Posted by matsp View Post
    The second attempt is what you get
    if you change "int" to "short" in the bit_t struct. Remember
    that the compiler will align the entire struct to the size of the
    basic type, so if you ACTUALLY want the struct to be 32 bits,
    you should use unsigned int, if you want it to be 16 bits, use
    unsigned short [or some other type that has a 16-bit size -
    this is typically a case for using "uint32_t" or "uint16_t".

    Is this what you meant by the compiler making "inefficient"
    code, because to me it is "you get what you ask for" type
    behaviour. There is no code accessing the bitfields in this
    example, so there's no inefficiency in that respect.

    Edit: I have no intention to edit Wikipedia, as at least the
    part you quoted I have no disagrement with.

    --
    Mats
    Thanks for the new idea indeed I tried that but since its easy
    to implement I leave it to ones who are interested to see
    what happens.

    I may encourage every one who want to get the idea to try
    his/her code for the padding problem of struct bitfields in C.
    One can easily add code for accessing them too ( for instance
    initialize them to some non zero value and so on ). Then use simple
    pointer arithmetic to measure the distance between two
    allocated bit_t type to see how much bits or bytes are used
    in practice and also it is easy to compare those numbers
    specially with what could be used using an appreciate
    unsigned variable.

    Also not that as already mentioned padding is only one of the
    problems of using struct bitfields comparing to the alternative
    way of using the suitable unsigned value and bit-wise
    operations.

    And no I will not continue this discussion; as a matter of fact I
    already did try the mentioned ideas above but since I might
    be biased on the results let me leave it to interested
    individuals to try those ideas on various situations
    (OSs,architectures,compilers) and if they find interesting
    things they might discuss them if they wish.

    So to sum it up IMO it is recommended to use an unsigned
    value of the appreciate type for many bitfields instead of
    struct bitfields; for those who care for efficiency anyway.

    Thanks every one and good bye.

  12. #27
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Right, I think we have covered almost everything that needs covering here.

    There is however a couple of point I'd like to point out:
    1. There are situations when a certain set of data items HAS TO FIT in a certain space. Typically, hardware registers that have multiple fields within a certain space (e.g. a 32-bit register that has more than one item of content). We have two choices as to how to solve that: Either define masks and shift values to manipulate the fields, or use bitfields. Yes, bitfields are potentially flawed, but it's a neat way to define it IF IT WORKS OK.

    One case may be the 16-bit colour combinations using RGB565 format:
    Code:
    	struct rgb
    	{
    		unsigned short r:5;
    		unsigned int g:6;
    		unsigned int b:5;
    	};
    2. It is rarely useful to use bitfields for software only situations. In this case, it's nearly always better to use fields of char, short, int, long and long long to represent the data. It gives better performance, and it's rarely meaningfull to try to squeeze the data into a smaller space.

    I wrote a little program to benchmark the difference in setting such an RGB setup with a couple of different solutions.
    Code:
    #include <time.h>
    #include <stdio.h>
    
    #define SIZE 100000
    
    void rgb1(void)
    {
    	struct rgb
    	{
    		unsigned short r:5;
    		unsigned short g:6;
    		unsigned short b:5;
    	};
    	static struct rgb arr[SIZE];
    	unsigned int i;
    	for(i = 0; i < SIZE; i++)
    	{
    		arr[i].r = i & 31;
    		arr[i].g = i & 63;
    		arr[i].b = (i >> 3) & 31;
    	}
    }
    
    #define RED(x, r) ((x) &= ~((1 << 5)-1) << 11, (x) |= ((r) << 11))
    #define GREEN(x, g) ((x) &= ~((1 << 6)-1) << 5, (x) |= ((g) << 5))
    #define BLUE(x, b) ((x) &= ~((1 << 5)-1), (x) |= (b))
    
    
    void rgb2(void)
    {
    	static unsigned short arr[SIZE];
    	unsigned int i;
    	for(i = 0; i < SIZE; i++)
    	{
    		RED(arr[i], i & 31);
    		GREEN(arr[i], i & 63);
    		BLUE(arr[i], (i >> 3) & 31);
    	}
    }
    
    void rgb3(void)
    {
    	struct rgb
    	{
    		unsigned char r;
    		unsigned char g;
    		unsigned char b;
    	};
    	static struct rgb arr[SIZE];
    	unsigned int i;
    	for(i = 0; i < SIZE; i++)
    	{
    		arr[i].r = i & 31;
    		arr[i].g = i & 63;
    		arr[i].b = (i >> 3) & 31;
    	}
    }
    
    
    void timeIt(char *name, void (*f)(void))
    {
    	int i = 0;
    	clock_t t = clock();
    	for(i = 0; i < 5000; i++)
    	{
    		f();
    	}
    	t = clock() - t;
    	printf("%s: %8.6f\n", name, (double)(t) / CLOCKS_PER_SEC);
    }
    
    
    #define TIME_IT(f) do { timeIt(#f, f); } while(0)
    
    int main()
    {
    	TIME_IT(rgb1);
    	TIME_IT(rgb2);
    	TIME_IT(rgb3);
            return 0;
    }
    With MS Visual Studio .Net:
    Code:
    rgb1: 1.515000
    rgb2: 1.313000
    rgb3: 1.281000
    So, not a whole lot of difference between the solutions, with the winner being the one using whole bytes - but only by a little bit. [rgb1 and rgb2 are only different in some minor details in the assembler code - the rgb1 version is using a partial-load sequence where a 32-bit register is cleared to zero, then loading the lowest byte, whilst the rgb2 uses a full 32-bit load in the first place.

    Using gcc-mingw:
    Code:
    rgb1: 7.781000
    rgb2: 1.234000
    rgb3: 1.281000
    Clearly, gcc-mingw misses out on a few "tricks" in the optimisation game here. Maybe someone who has access to gcc 4.x can try it out and see if that version has done a better job.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bit manipulation
    By Neo1 in forum C++ Programming
    Replies: 8
    Last Post: 03-24-2008, 11:53 AM
  2. bitfield "array"
    By bibsik in forum C++ Programming
    Replies: 6
    Last Post: 04-13-2006, 12:34 AM
  3. bits & bytes
    By pelom in forum C Programming
    Replies: 8
    Last Post: 10-11-2005, 09:45 AM
  4. bitfield memory question
    By sufthingol in forum C++ Programming
    Replies: 19
    Last Post: 03-26-2005, 04:43 PM
  5. Structure definition
    By Unregistered in forum C Programming
    Replies: 18
    Last Post: 07-31-2002, 09:52 AM