Bit manipulations good practices

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
6
down vote

favorite












As a beginner C programmer, I am wondering, what would be the best easy-to-read and easy-to-understand solution for setting control bits in a device. Are there any standards? Any example code to mimic? Google didn't give any reliable answer.



For example, I have a control block map:
map



The first way I see would be to simply set the needed bits. It requires a bunch of explanations in comments and seems to be not all that professional.



DMA_base_ptr[DMA_CONTROL_OFFS] = 0b10001100;


The second way I see is to create a bit field. I'm not sure if this is the one should I stick to, since I never encountered it being used in such way (unlike the first option I mentioned).



struct DMA_control_block_struct

unsigned int BYTE:1;
unsigned int HW:1;
// etc
DMA_control_block_struct;


Is one of the options better than the other one? Are there any options I just don't see?



Any advice would be highly appreciated










share|improve this question









New contributor




KateOleneva is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.



















  • By the way, using 0b for base-two constants is nonstandard.
    – Steve Summit
    37 mins ago














up vote
6
down vote

favorite












As a beginner C programmer, I am wondering, what would be the best easy-to-read and easy-to-understand solution for setting control bits in a device. Are there any standards? Any example code to mimic? Google didn't give any reliable answer.



For example, I have a control block map:
map



The first way I see would be to simply set the needed bits. It requires a bunch of explanations in comments and seems to be not all that professional.



DMA_base_ptr[DMA_CONTROL_OFFS] = 0b10001100;


The second way I see is to create a bit field. I'm not sure if this is the one should I stick to, since I never encountered it being used in such way (unlike the first option I mentioned).



struct DMA_control_block_struct

unsigned int BYTE:1;
unsigned int HW:1;
// etc
DMA_control_block_struct;


Is one of the options better than the other one? Are there any options I just don't see?



Any advice would be highly appreciated










share|improve this question









New contributor




KateOleneva is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.



















  • By the way, using 0b for base-two constants is nonstandard.
    – Steve Summit
    37 mins ago












up vote
6
down vote

favorite









up vote
6
down vote

favorite











As a beginner C programmer, I am wondering, what would be the best easy-to-read and easy-to-understand solution for setting control bits in a device. Are there any standards? Any example code to mimic? Google didn't give any reliable answer.



For example, I have a control block map:
map



The first way I see would be to simply set the needed bits. It requires a bunch of explanations in comments and seems to be not all that professional.



DMA_base_ptr[DMA_CONTROL_OFFS] = 0b10001100;


The second way I see is to create a bit field. I'm not sure if this is the one should I stick to, since I never encountered it being used in such way (unlike the first option I mentioned).



struct DMA_control_block_struct

unsigned int BYTE:1;
unsigned int HW:1;
// etc
DMA_control_block_struct;


Is one of the options better than the other one? Are there any options I just don't see?



Any advice would be highly appreciated










share|improve this question









New contributor




KateOleneva is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











As a beginner C programmer, I am wondering, what would be the best easy-to-read and easy-to-understand solution for setting control bits in a device. Are there any standards? Any example code to mimic? Google didn't give any reliable answer.



For example, I have a control block map:
map



The first way I see would be to simply set the needed bits. It requires a bunch of explanations in comments and seems to be not all that professional.



DMA_base_ptr[DMA_CONTROL_OFFS] = 0b10001100;


The second way I see is to create a bit field. I'm not sure if this is the one should I stick to, since I never encountered it being used in such way (unlike the first option I mentioned).



struct DMA_control_block_struct

unsigned int BYTE:1;
unsigned int HW:1;
// etc
DMA_control_block_struct;


Is one of the options better than the other one? Are there any options I just don't see?



Any advice would be highly appreciated







c standards bit






share|improve this question









New contributor




KateOleneva is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




KateOleneva is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 54 mins ago





















New contributor




KateOleneva is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 1 hour ago









KateOleneva

364




364




New contributor




KateOleneva is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





KateOleneva is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






KateOleneva is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











  • By the way, using 0b for base-two constants is nonstandard.
    – Steve Summit
    37 mins ago
















  • By the way, using 0b for base-two constants is nonstandard.
    – Steve Summit
    37 mins ago















By the way, using 0b for base-two constants is nonstandard.
– Steve Summit
37 mins ago




By the way, using 0b for base-two constants is nonstandard.
– Steve Summit
37 mins ago












6 Answers
6






active

oldest

votes

















up vote
6
down vote



accepted










The problem with bit fields is that the C standard does not dictate that the order in which they are defined is the same as the order that they are implemented. So you may not be setting the bits you think you are.



Section 6.7.2.1p11 of the C standard states:




An implementation may allocate any addressable storage unit large
enough to hold a bit- field. If enough space remains, a bit-field
that immediately follows another bit-field in a structure shall be
packed into adjacent bits of the same unit. If insufficient space
remains, whether a bit-field that does not fit is put into
the next unit or overlaps adjacent units is
implementation-defined. The order of allocation of bit-fields within
a unit (high-order to low-order or low-order to high-order) is
implementation-defined.
The alignment of the addressable storage
unit is unspecified.




As an example, look at the definition of struct iphdr, which represents an IP header, from the /usr/include/netinet/ip.h file file on Linux:



struct iphdr
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ihl:4;
unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int version:4;
unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
u_int8_t tos;
...


You can see here that the bitfields are placed in a different order depending on the implementation. You also shouldn't use this specific check because this behavior is system dependent. It is acceptable for this file because it is part of the system. Other systems may implement this in different ways.



So don't use a bitfield.



The best way to do this is to set the required bits. However, it would make sense to define named constants for each bit and to perform a bitwise OR of the constants you want to set. For example:



const uint8_t BIT_BYTE = 0x1;
const uint8_t BIT_HW = 0x2;
const uint8_t BIT_WORD = 0x4;
const uint8_t BIT_GO = 0x8;
const uint8_t BIT_I_EN = 0x10;
const uint8_t BIT_REEN = 0x20;
const uint8_t BIT_WEEN = 0x40;
const uint8_t BIT_LEEN = 0x80;

DMA_base_ptr[DMA_CONTROL_OFFS] = BIT_LEEN | BIT_GO | BIT_WORD;





share|improve this answer


















  • 1




    It is acceptable for this file because it is part of the system. It's also "acceptable" because Linux pretty much de facto requires GCC to compile. A different compiler is free to change how the bit fields are assigned even if the endianness remains the same.
    – Andrew Henle
    56 mins ago

















up vote
4
down vote













The old-school C way is to define a bunch of bits:



#define WORD 0x04
#define GO 0x08
#define I_EN 0x10
#define LEEN 0x80


Then your initialization becomes



DMA_base_ptr[DMA_CONTROL_OFFS] = WORD | GO | LEEN;


You can set individual bits using |:



DMA_base_ptr[DMA_CONTROL_OFFS] |= I_EN;


You can clear individual bits using & and ~:



DMA_base_ptr[DMA_CONTROL_OFFS] &= ~GO;


You can test individual bits using &:



if(DMA_base_ptr[DMA_CONTROL_OFFS] & WORD) ...


Definitely don't use bitfields, though. They have their uses, but not when an external specification defines that the bits are in certain places, as I assume is the case here.



See also questions 20.7 and 2.26 in the C FAQ list.






share|improve this answer






















  • Can't you just determine the bit order by referencing the stdlib.h and stddef.h header files for a particular system?
    – Clay Raynor
    1 hour ago










  • I see no fundamental problem with using bit fields to match hardware registers on a particular embedded platform, for example, since the code tends to be inherently non-portable in any case (tied to that specific device and often either a single compiler). The gains in readability and convenience for multi-bit fields in particular can be worth it. (Of course there may be other problems, such as code size or performance, that need to be checked, but my point is that I wouldn't disregard bit fields for this use automatically.)
    – Arkku
    1 hour ago










  • Just be careful when using ~ because it contains an implicit integer promotion. Good practice is to cast back to the intended type: DMA_base_ptr[DMA_CONTROL_OFFS] &= (uint8_t)~WRITEACCESS;
    – Lundin
    1 hour ago










  • Thank you for the answer, I find the details on usage extremely helpful and will definitely use a thing or two
    – KateOleneva
    1 hour ago










  • @Arkku, ClayRaynor: In the end it's something of a matter of style. In my opinion, trying to get an in-memory data structure to conform to an externally-imposed storage layout is simply more trouble than it's worth. It may be a minority opinion, though, because certainly, vast numbers of C programmers spend vast amounts of time trying to arrange such conformances. (And sometimes, of course, they succeed, including when they're matching individual bits with bitfields.)
    – Steve Summit
    52 mins ago


















up vote
2
down vote













Other answers have already covered most of the stuff, but it might be worthwhile to mention that even if you can't use the non-standard 0b syntax, you can use shifts to move the 1 bit into position by bit number, i.e.:



#define DMA_BYTE (1U << 0)
#define DMA_HW (1U << 1)
#define DMA_WORD (1U << 2)
#define DMA_GO (1U << 3)
// …


Note how the last number matches the "bit number" column in the documentation.



The usage for setting and clearing bits doesn't change:



#define DMA_CONTROL_REG DMA_base_ptr[DMA_CONTROL_OFFS]

DMA_CONTROL_REG |= DMA_HW | DMA_WORD; // set HW and WORD
DMA_CONTROL_REG &= ~(DMA_BYTE | DMA_GO); // clear BYTE and GO





share|improve this answer



























    up vote
    0
    down vote













    You should make sure to initialize the bits to a known default value when you declare the variable to store their values. In C, when you declare a variable you are just reserving a block of memory at a address and the size of the block is based its type. If you don't initialize the variable you can encounter undefined / unexpected behavior since the value of the variable will be effected by whatever the value / state of the memory in that block was before you declared it. By initializing the variable to a default value, you are clearing this block of memory of its existing state and putting it in a know state.



    As far as readability, you should use a bit field to store the values of the bit. A bit field enables you to store the values of the bits in a struct. This makes it easier to organize since you can use dot notation. Also, you should make sure to comment the declaration of the bit field to explain what the different fields are used for as a best practice. I hope this answers your question. Good luck with you C programming!






    share|improve this answer




















    • Bit fields are extremely non-portable. Any compiler can do what it wants. Per 6.7.2.1 Structure and union specifiers, paragraph 11 of the C standard: "... whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified."
      – Andrew Henle
      50 mins ago


















    up vote
    0
    down vote













    There is no standard for bit fields. Mapping and bit operation are dependent on compiler in this case. Binary values such as 0b0000 are not standardized also. Usual way to do is defining hexadecimal values for each bit. For example:



    #define BYTE (0x01)
    #define HW (0x02)
    /*etc*/


    When you want to set bits, you can use:



    DMA_base_ptr[DMA_CONTROL_OFFS] |= HW;


    Or you can clear bits with:



    DMA_base_ptr[DMA_CONTROL_OFFS] &= ~HW;





    share|improve this answer








    New contributor




    kurtfu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.
























      up vote
      0
      down vote













      Modern C compilers handle trivial inline functions just fine – without overhead. I’d make all of the abstractions functions, so that the user doesn’t need to manipulate any bits or integers, and is unlikely to abuse the implementation details.



      You can of course use constants and not functions for implementation details, but the API should be functions. This also allows using macros instead of functions if you’re using an ancient compiler.



      For example:



      #include <stdbool.h>
      #include <stdint.h>

      typedef union DmaBase
      volatile uint8_t u8[32];
      DmaBase;
      static inline DmaBase *const dma1__base(void) return (void*)0x12340000;

      // instead of DMA_CONTROL_OFFS
      static inline volatile uint8_t *dma_CONTROL(DmaBase *base) return &(base->u8[12]);
      // instead of constants etc
      static inline uint8_t dma__BYTE(void) return 0x01;

      inline bool dma_BYTE(DmaBase *base) return *dma_CONTROL(base) & dma__BYTE();
      inline void dma_set_BYTE(DmaBase *base, bool val)
      if (val) *dma_CONTROL(base)
      inline bool dma1_BYTE(void) return dma_BYTE(dma1__base());
      inline void dma1_set_BYTE(bool val) dma_set_BYTE(dma1__base(), val);





      share|improve this answer




















        Your Answer






        StackExchange.ifUsing("editor", function ()
        StackExchange.using("externalEditor", function ()
        StackExchange.using("snippets", function ()
        StackExchange.snippets.init();
        );
        );
        , "code-snippets");

        StackExchange.ready(function()
        var channelOptions =
        tags: "".split(" "),
        id: "1"
        ;
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function()
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled)
        StackExchange.using("snippets", function()
        createEditor();
        );

        else
        createEditor();

        );

        function createEditor()
        StackExchange.prepareEditor(
        heartbeatType: 'answer',
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader:
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        ,
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        );



        );






        KateOleneva is a new contributor. Be nice, and check out our Code of Conduct.









         

        draft saved


        draft discarded


















        StackExchange.ready(
        function ()
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53118858%2fbit-manipulations-good-practices%23new-answer', 'question_page');

        );

        Post as a guest






























        6 Answers
        6






        active

        oldest

        votes








        6 Answers
        6






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes








        up vote
        6
        down vote



        accepted










        The problem with bit fields is that the C standard does not dictate that the order in which they are defined is the same as the order that they are implemented. So you may not be setting the bits you think you are.



        Section 6.7.2.1p11 of the C standard states:




        An implementation may allocate any addressable storage unit large
        enough to hold a bit- field. If enough space remains, a bit-field
        that immediately follows another bit-field in a structure shall be
        packed into adjacent bits of the same unit. If insufficient space
        remains, whether a bit-field that does not fit is put into
        the next unit or overlaps adjacent units is
        implementation-defined. The order of allocation of bit-fields within
        a unit (high-order to low-order or low-order to high-order) is
        implementation-defined.
        The alignment of the addressable storage
        unit is unspecified.




        As an example, look at the definition of struct iphdr, which represents an IP header, from the /usr/include/netinet/ip.h file file on Linux:



        struct iphdr
        {
        #if __BYTE_ORDER == __LITTLE_ENDIAN
        unsigned int ihl:4;
        unsigned int version:4;
        #elif __BYTE_ORDER == __BIG_ENDIAN
        unsigned int version:4;
        unsigned int ihl:4;
        #else
        # error "Please fix <bits/endian.h>"
        #endif
        u_int8_t tos;
        ...


        You can see here that the bitfields are placed in a different order depending on the implementation. You also shouldn't use this specific check because this behavior is system dependent. It is acceptable for this file because it is part of the system. Other systems may implement this in different ways.



        So don't use a bitfield.



        The best way to do this is to set the required bits. However, it would make sense to define named constants for each bit and to perform a bitwise OR of the constants you want to set. For example:



        const uint8_t BIT_BYTE = 0x1;
        const uint8_t BIT_HW = 0x2;
        const uint8_t BIT_WORD = 0x4;
        const uint8_t BIT_GO = 0x8;
        const uint8_t BIT_I_EN = 0x10;
        const uint8_t BIT_REEN = 0x20;
        const uint8_t BIT_WEEN = 0x40;
        const uint8_t BIT_LEEN = 0x80;

        DMA_base_ptr[DMA_CONTROL_OFFS] = BIT_LEEN | BIT_GO | BIT_WORD;





        share|improve this answer


















        • 1




          It is acceptable for this file because it is part of the system. It's also "acceptable" because Linux pretty much de facto requires GCC to compile. A different compiler is free to change how the bit fields are assigned even if the endianness remains the same.
          – Andrew Henle
          56 mins ago














        up vote
        6
        down vote



        accepted










        The problem with bit fields is that the C standard does not dictate that the order in which they are defined is the same as the order that they are implemented. So you may not be setting the bits you think you are.



        Section 6.7.2.1p11 of the C standard states:




        An implementation may allocate any addressable storage unit large
        enough to hold a bit- field. If enough space remains, a bit-field
        that immediately follows another bit-field in a structure shall be
        packed into adjacent bits of the same unit. If insufficient space
        remains, whether a bit-field that does not fit is put into
        the next unit or overlaps adjacent units is
        implementation-defined. The order of allocation of bit-fields within
        a unit (high-order to low-order or low-order to high-order) is
        implementation-defined.
        The alignment of the addressable storage
        unit is unspecified.




        As an example, look at the definition of struct iphdr, which represents an IP header, from the /usr/include/netinet/ip.h file file on Linux:



        struct iphdr
        {
        #if __BYTE_ORDER == __LITTLE_ENDIAN
        unsigned int ihl:4;
        unsigned int version:4;
        #elif __BYTE_ORDER == __BIG_ENDIAN
        unsigned int version:4;
        unsigned int ihl:4;
        #else
        # error "Please fix <bits/endian.h>"
        #endif
        u_int8_t tos;
        ...


        You can see here that the bitfields are placed in a different order depending on the implementation. You also shouldn't use this specific check because this behavior is system dependent. It is acceptable for this file because it is part of the system. Other systems may implement this in different ways.



        So don't use a bitfield.



        The best way to do this is to set the required bits. However, it would make sense to define named constants for each bit and to perform a bitwise OR of the constants you want to set. For example:



        const uint8_t BIT_BYTE = 0x1;
        const uint8_t BIT_HW = 0x2;
        const uint8_t BIT_WORD = 0x4;
        const uint8_t BIT_GO = 0x8;
        const uint8_t BIT_I_EN = 0x10;
        const uint8_t BIT_REEN = 0x20;
        const uint8_t BIT_WEEN = 0x40;
        const uint8_t BIT_LEEN = 0x80;

        DMA_base_ptr[DMA_CONTROL_OFFS] = BIT_LEEN | BIT_GO | BIT_WORD;





        share|improve this answer


















        • 1




          It is acceptable for this file because it is part of the system. It's also "acceptable" because Linux pretty much de facto requires GCC to compile. A different compiler is free to change how the bit fields are assigned even if the endianness remains the same.
          – Andrew Henle
          56 mins ago












        up vote
        6
        down vote



        accepted







        up vote
        6
        down vote



        accepted






        The problem with bit fields is that the C standard does not dictate that the order in which they are defined is the same as the order that they are implemented. So you may not be setting the bits you think you are.



        Section 6.7.2.1p11 of the C standard states:




        An implementation may allocate any addressable storage unit large
        enough to hold a bit- field. If enough space remains, a bit-field
        that immediately follows another bit-field in a structure shall be
        packed into adjacent bits of the same unit. If insufficient space
        remains, whether a bit-field that does not fit is put into
        the next unit or overlaps adjacent units is
        implementation-defined. The order of allocation of bit-fields within
        a unit (high-order to low-order or low-order to high-order) is
        implementation-defined.
        The alignment of the addressable storage
        unit is unspecified.




        As an example, look at the definition of struct iphdr, which represents an IP header, from the /usr/include/netinet/ip.h file file on Linux:



        struct iphdr
        {
        #if __BYTE_ORDER == __LITTLE_ENDIAN
        unsigned int ihl:4;
        unsigned int version:4;
        #elif __BYTE_ORDER == __BIG_ENDIAN
        unsigned int version:4;
        unsigned int ihl:4;
        #else
        # error "Please fix <bits/endian.h>"
        #endif
        u_int8_t tos;
        ...


        You can see here that the bitfields are placed in a different order depending on the implementation. You also shouldn't use this specific check because this behavior is system dependent. It is acceptable for this file because it is part of the system. Other systems may implement this in different ways.



        So don't use a bitfield.



        The best way to do this is to set the required bits. However, it would make sense to define named constants for each bit and to perform a bitwise OR of the constants you want to set. For example:



        const uint8_t BIT_BYTE = 0x1;
        const uint8_t BIT_HW = 0x2;
        const uint8_t BIT_WORD = 0x4;
        const uint8_t BIT_GO = 0x8;
        const uint8_t BIT_I_EN = 0x10;
        const uint8_t BIT_REEN = 0x20;
        const uint8_t BIT_WEEN = 0x40;
        const uint8_t BIT_LEEN = 0x80;

        DMA_base_ptr[DMA_CONTROL_OFFS] = BIT_LEEN | BIT_GO | BIT_WORD;





        share|improve this answer














        The problem with bit fields is that the C standard does not dictate that the order in which they are defined is the same as the order that they are implemented. So you may not be setting the bits you think you are.



        Section 6.7.2.1p11 of the C standard states:




        An implementation may allocate any addressable storage unit large
        enough to hold a bit- field. If enough space remains, a bit-field
        that immediately follows another bit-field in a structure shall be
        packed into adjacent bits of the same unit. If insufficient space
        remains, whether a bit-field that does not fit is put into
        the next unit or overlaps adjacent units is
        implementation-defined. The order of allocation of bit-fields within
        a unit (high-order to low-order or low-order to high-order) is
        implementation-defined.
        The alignment of the addressable storage
        unit is unspecified.




        As an example, look at the definition of struct iphdr, which represents an IP header, from the /usr/include/netinet/ip.h file file on Linux:



        struct iphdr
        {
        #if __BYTE_ORDER == __LITTLE_ENDIAN
        unsigned int ihl:4;
        unsigned int version:4;
        #elif __BYTE_ORDER == __BIG_ENDIAN
        unsigned int version:4;
        unsigned int ihl:4;
        #else
        # error "Please fix <bits/endian.h>"
        #endif
        u_int8_t tos;
        ...


        You can see here that the bitfields are placed in a different order depending on the implementation. You also shouldn't use this specific check because this behavior is system dependent. It is acceptable for this file because it is part of the system. Other systems may implement this in different ways.



        So don't use a bitfield.



        The best way to do this is to set the required bits. However, it would make sense to define named constants for each bit and to perform a bitwise OR of the constants you want to set. For example:



        const uint8_t BIT_BYTE = 0x1;
        const uint8_t BIT_HW = 0x2;
        const uint8_t BIT_WORD = 0x4;
        const uint8_t BIT_GO = 0x8;
        const uint8_t BIT_I_EN = 0x10;
        const uint8_t BIT_REEN = 0x20;
        const uint8_t BIT_WEEN = 0x40;
        const uint8_t BIT_LEEN = 0x80;

        DMA_base_ptr[DMA_CONTROL_OFFS] = BIT_LEEN | BIT_GO | BIT_WORD;






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 1 min ago

























        answered 1 hour ago









        dbush

        87.1k1093125




        87.1k1093125







        • 1




          It is acceptable for this file because it is part of the system. It's also "acceptable" because Linux pretty much de facto requires GCC to compile. A different compiler is free to change how the bit fields are assigned even if the endianness remains the same.
          – Andrew Henle
          56 mins ago












        • 1




          It is acceptable for this file because it is part of the system. It's also "acceptable" because Linux pretty much de facto requires GCC to compile. A different compiler is free to change how the bit fields are assigned even if the endianness remains the same.
          – Andrew Henle
          56 mins ago







        1




        1




        It is acceptable for this file because it is part of the system. It's also "acceptable" because Linux pretty much de facto requires GCC to compile. A different compiler is free to change how the bit fields are assigned even if the endianness remains the same.
        – Andrew Henle
        56 mins ago




        It is acceptable for this file because it is part of the system. It's also "acceptable" because Linux pretty much de facto requires GCC to compile. A different compiler is free to change how the bit fields are assigned even if the endianness remains the same.
        – Andrew Henle
        56 mins ago












        up vote
        4
        down vote













        The old-school C way is to define a bunch of bits:



        #define WORD 0x04
        #define GO 0x08
        #define I_EN 0x10
        #define LEEN 0x80


        Then your initialization becomes



        DMA_base_ptr[DMA_CONTROL_OFFS] = WORD | GO | LEEN;


        You can set individual bits using |:



        DMA_base_ptr[DMA_CONTROL_OFFS] |= I_EN;


        You can clear individual bits using & and ~:



        DMA_base_ptr[DMA_CONTROL_OFFS] &= ~GO;


        You can test individual bits using &:



        if(DMA_base_ptr[DMA_CONTROL_OFFS] & WORD) ...


        Definitely don't use bitfields, though. They have their uses, but not when an external specification defines that the bits are in certain places, as I assume is the case here.



        See also questions 20.7 and 2.26 in the C FAQ list.






        share|improve this answer






















        • Can't you just determine the bit order by referencing the stdlib.h and stddef.h header files for a particular system?
          – Clay Raynor
          1 hour ago










        • I see no fundamental problem with using bit fields to match hardware registers on a particular embedded platform, for example, since the code tends to be inherently non-portable in any case (tied to that specific device and often either a single compiler). The gains in readability and convenience for multi-bit fields in particular can be worth it. (Of course there may be other problems, such as code size or performance, that need to be checked, but my point is that I wouldn't disregard bit fields for this use automatically.)
          – Arkku
          1 hour ago










        • Just be careful when using ~ because it contains an implicit integer promotion. Good practice is to cast back to the intended type: DMA_base_ptr[DMA_CONTROL_OFFS] &= (uint8_t)~WRITEACCESS;
          – Lundin
          1 hour ago










        • Thank you for the answer, I find the details on usage extremely helpful and will definitely use a thing or two
          – KateOleneva
          1 hour ago










        • @Arkku, ClayRaynor: In the end it's something of a matter of style. In my opinion, trying to get an in-memory data structure to conform to an externally-imposed storage layout is simply more trouble than it's worth. It may be a minority opinion, though, because certainly, vast numbers of C programmers spend vast amounts of time trying to arrange such conformances. (And sometimes, of course, they succeed, including when they're matching individual bits with bitfields.)
          – Steve Summit
          52 mins ago















        up vote
        4
        down vote













        The old-school C way is to define a bunch of bits:



        #define WORD 0x04
        #define GO 0x08
        #define I_EN 0x10
        #define LEEN 0x80


        Then your initialization becomes



        DMA_base_ptr[DMA_CONTROL_OFFS] = WORD | GO | LEEN;


        You can set individual bits using |:



        DMA_base_ptr[DMA_CONTROL_OFFS] |= I_EN;


        You can clear individual bits using & and ~:



        DMA_base_ptr[DMA_CONTROL_OFFS] &= ~GO;


        You can test individual bits using &:



        if(DMA_base_ptr[DMA_CONTROL_OFFS] & WORD) ...


        Definitely don't use bitfields, though. They have their uses, but not when an external specification defines that the bits are in certain places, as I assume is the case here.



        See also questions 20.7 and 2.26 in the C FAQ list.






        share|improve this answer






















        • Can't you just determine the bit order by referencing the stdlib.h and stddef.h header files for a particular system?
          – Clay Raynor
          1 hour ago










        • I see no fundamental problem with using bit fields to match hardware registers on a particular embedded platform, for example, since the code tends to be inherently non-portable in any case (tied to that specific device and often either a single compiler). The gains in readability and convenience for multi-bit fields in particular can be worth it. (Of course there may be other problems, such as code size or performance, that need to be checked, but my point is that I wouldn't disregard bit fields for this use automatically.)
          – Arkku
          1 hour ago










        • Just be careful when using ~ because it contains an implicit integer promotion. Good practice is to cast back to the intended type: DMA_base_ptr[DMA_CONTROL_OFFS] &= (uint8_t)~WRITEACCESS;
          – Lundin
          1 hour ago










        • Thank you for the answer, I find the details on usage extremely helpful and will definitely use a thing or two
          – KateOleneva
          1 hour ago










        • @Arkku, ClayRaynor: In the end it's something of a matter of style. In my opinion, trying to get an in-memory data structure to conform to an externally-imposed storage layout is simply more trouble than it's worth. It may be a minority opinion, though, because certainly, vast numbers of C programmers spend vast amounts of time trying to arrange such conformances. (And sometimes, of course, they succeed, including when they're matching individual bits with bitfields.)
          – Steve Summit
          52 mins ago













        up vote
        4
        down vote










        up vote
        4
        down vote









        The old-school C way is to define a bunch of bits:



        #define WORD 0x04
        #define GO 0x08
        #define I_EN 0x10
        #define LEEN 0x80


        Then your initialization becomes



        DMA_base_ptr[DMA_CONTROL_OFFS] = WORD | GO | LEEN;


        You can set individual bits using |:



        DMA_base_ptr[DMA_CONTROL_OFFS] |= I_EN;


        You can clear individual bits using & and ~:



        DMA_base_ptr[DMA_CONTROL_OFFS] &= ~GO;


        You can test individual bits using &:



        if(DMA_base_ptr[DMA_CONTROL_OFFS] & WORD) ...


        Definitely don't use bitfields, though. They have their uses, but not when an external specification defines that the bits are in certain places, as I assume is the case here.



        See also questions 20.7 and 2.26 in the C FAQ list.






        share|improve this answer














        The old-school C way is to define a bunch of bits:



        #define WORD 0x04
        #define GO 0x08
        #define I_EN 0x10
        #define LEEN 0x80


        Then your initialization becomes



        DMA_base_ptr[DMA_CONTROL_OFFS] = WORD | GO | LEEN;


        You can set individual bits using |:



        DMA_base_ptr[DMA_CONTROL_OFFS] |= I_EN;


        You can clear individual bits using & and ~:



        DMA_base_ptr[DMA_CONTROL_OFFS] &= ~GO;


        You can test individual bits using &:



        if(DMA_base_ptr[DMA_CONTROL_OFFS] & WORD) ...


        Definitely don't use bitfields, though. They have their uses, but not when an external specification defines that the bits are in certain places, as I assume is the case here.



        See also questions 20.7 and 2.26 in the C FAQ list.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 47 mins ago

























        answered 1 hour ago









        Steve Summit

        17.2k22447




        17.2k22447











        • Can't you just determine the bit order by referencing the stdlib.h and stddef.h header files for a particular system?
          – Clay Raynor
          1 hour ago










        • I see no fundamental problem with using bit fields to match hardware registers on a particular embedded platform, for example, since the code tends to be inherently non-portable in any case (tied to that specific device and often either a single compiler). The gains in readability and convenience for multi-bit fields in particular can be worth it. (Of course there may be other problems, such as code size or performance, that need to be checked, but my point is that I wouldn't disregard bit fields for this use automatically.)
          – Arkku
          1 hour ago










        • Just be careful when using ~ because it contains an implicit integer promotion. Good practice is to cast back to the intended type: DMA_base_ptr[DMA_CONTROL_OFFS] &= (uint8_t)~WRITEACCESS;
          – Lundin
          1 hour ago










        • Thank you for the answer, I find the details on usage extremely helpful and will definitely use a thing or two
          – KateOleneva
          1 hour ago










        • @Arkku, ClayRaynor: In the end it's something of a matter of style. In my opinion, trying to get an in-memory data structure to conform to an externally-imposed storage layout is simply more trouble than it's worth. It may be a minority opinion, though, because certainly, vast numbers of C programmers spend vast amounts of time trying to arrange such conformances. (And sometimes, of course, they succeed, including when they're matching individual bits with bitfields.)
          – Steve Summit
          52 mins ago

















        • Can't you just determine the bit order by referencing the stdlib.h and stddef.h header files for a particular system?
          – Clay Raynor
          1 hour ago










        • I see no fundamental problem with using bit fields to match hardware registers on a particular embedded platform, for example, since the code tends to be inherently non-portable in any case (tied to that specific device and often either a single compiler). The gains in readability and convenience for multi-bit fields in particular can be worth it. (Of course there may be other problems, such as code size or performance, that need to be checked, but my point is that I wouldn't disregard bit fields for this use automatically.)
          – Arkku
          1 hour ago










        • Just be careful when using ~ because it contains an implicit integer promotion. Good practice is to cast back to the intended type: DMA_base_ptr[DMA_CONTROL_OFFS] &= (uint8_t)~WRITEACCESS;
          – Lundin
          1 hour ago










        • Thank you for the answer, I find the details on usage extremely helpful and will definitely use a thing or two
          – KateOleneva
          1 hour ago










        • @Arkku, ClayRaynor: In the end it's something of a matter of style. In my opinion, trying to get an in-memory data structure to conform to an externally-imposed storage layout is simply more trouble than it's worth. It may be a minority opinion, though, because certainly, vast numbers of C programmers spend vast amounts of time trying to arrange such conformances. (And sometimes, of course, they succeed, including when they're matching individual bits with bitfields.)
          – Steve Summit
          52 mins ago
















        Can't you just determine the bit order by referencing the stdlib.h and stddef.h header files for a particular system?
        – Clay Raynor
        1 hour ago




        Can't you just determine the bit order by referencing the stdlib.h and stddef.h header files for a particular system?
        – Clay Raynor
        1 hour ago












        I see no fundamental problem with using bit fields to match hardware registers on a particular embedded platform, for example, since the code tends to be inherently non-portable in any case (tied to that specific device and often either a single compiler). The gains in readability and convenience for multi-bit fields in particular can be worth it. (Of course there may be other problems, such as code size or performance, that need to be checked, but my point is that I wouldn't disregard bit fields for this use automatically.)
        – Arkku
        1 hour ago




        I see no fundamental problem with using bit fields to match hardware registers on a particular embedded platform, for example, since the code tends to be inherently non-portable in any case (tied to that specific device and often either a single compiler). The gains in readability and convenience for multi-bit fields in particular can be worth it. (Of course there may be other problems, such as code size or performance, that need to be checked, but my point is that I wouldn't disregard bit fields for this use automatically.)
        – Arkku
        1 hour ago












        Just be careful when using ~ because it contains an implicit integer promotion. Good practice is to cast back to the intended type: DMA_base_ptr[DMA_CONTROL_OFFS] &= (uint8_t)~WRITEACCESS;
        – Lundin
        1 hour ago




        Just be careful when using ~ because it contains an implicit integer promotion. Good practice is to cast back to the intended type: DMA_base_ptr[DMA_CONTROL_OFFS] &= (uint8_t)~WRITEACCESS;
        – Lundin
        1 hour ago












        Thank you for the answer, I find the details on usage extremely helpful and will definitely use a thing or two
        – KateOleneva
        1 hour ago




        Thank you for the answer, I find the details on usage extremely helpful and will definitely use a thing or two
        – KateOleneva
        1 hour ago












        @Arkku, ClayRaynor: In the end it's something of a matter of style. In my opinion, trying to get an in-memory data structure to conform to an externally-imposed storage layout is simply more trouble than it's worth. It may be a minority opinion, though, because certainly, vast numbers of C programmers spend vast amounts of time trying to arrange such conformances. (And sometimes, of course, they succeed, including when they're matching individual bits with bitfields.)
        – Steve Summit
        52 mins ago





        @Arkku, ClayRaynor: In the end it's something of a matter of style. In my opinion, trying to get an in-memory data structure to conform to an externally-imposed storage layout is simply more trouble than it's worth. It may be a minority opinion, though, because certainly, vast numbers of C programmers spend vast amounts of time trying to arrange such conformances. (And sometimes, of course, they succeed, including when they're matching individual bits with bitfields.)
        – Steve Summit
        52 mins ago











        up vote
        2
        down vote













        Other answers have already covered most of the stuff, but it might be worthwhile to mention that even if you can't use the non-standard 0b syntax, you can use shifts to move the 1 bit into position by bit number, i.e.:



        #define DMA_BYTE (1U << 0)
        #define DMA_HW (1U << 1)
        #define DMA_WORD (1U << 2)
        #define DMA_GO (1U << 3)
        // …


        Note how the last number matches the "bit number" column in the documentation.



        The usage for setting and clearing bits doesn't change:



        #define DMA_CONTROL_REG DMA_base_ptr[DMA_CONTROL_OFFS]

        DMA_CONTROL_REG |= DMA_HW | DMA_WORD; // set HW and WORD
        DMA_CONTROL_REG &= ~(DMA_BYTE | DMA_GO); // clear BYTE and GO





        share|improve this answer
























          up vote
          2
          down vote













          Other answers have already covered most of the stuff, but it might be worthwhile to mention that even if you can't use the non-standard 0b syntax, you can use shifts to move the 1 bit into position by bit number, i.e.:



          #define DMA_BYTE (1U << 0)
          #define DMA_HW (1U << 1)
          #define DMA_WORD (1U << 2)
          #define DMA_GO (1U << 3)
          // …


          Note how the last number matches the "bit number" column in the documentation.



          The usage for setting and clearing bits doesn't change:



          #define DMA_CONTROL_REG DMA_base_ptr[DMA_CONTROL_OFFS]

          DMA_CONTROL_REG |= DMA_HW | DMA_WORD; // set HW and WORD
          DMA_CONTROL_REG &= ~(DMA_BYTE | DMA_GO); // clear BYTE and GO





          share|improve this answer






















            up vote
            2
            down vote










            up vote
            2
            down vote









            Other answers have already covered most of the stuff, but it might be worthwhile to mention that even if you can't use the non-standard 0b syntax, you can use shifts to move the 1 bit into position by bit number, i.e.:



            #define DMA_BYTE (1U << 0)
            #define DMA_HW (1U << 1)
            #define DMA_WORD (1U << 2)
            #define DMA_GO (1U << 3)
            // …


            Note how the last number matches the "bit number" column in the documentation.



            The usage for setting and clearing bits doesn't change:



            #define DMA_CONTROL_REG DMA_base_ptr[DMA_CONTROL_OFFS]

            DMA_CONTROL_REG |= DMA_HW | DMA_WORD; // set HW and WORD
            DMA_CONTROL_REG &= ~(DMA_BYTE | DMA_GO); // clear BYTE and GO





            share|improve this answer












            Other answers have already covered most of the stuff, but it might be worthwhile to mention that even if you can't use the non-standard 0b syntax, you can use shifts to move the 1 bit into position by bit number, i.e.:



            #define DMA_BYTE (1U << 0)
            #define DMA_HW (1U << 1)
            #define DMA_WORD (1U << 2)
            #define DMA_GO (1U << 3)
            // …


            Note how the last number matches the "bit number" column in the documentation.



            The usage for setting and clearing bits doesn't change:



            #define DMA_CONTROL_REG DMA_base_ptr[DMA_CONTROL_OFFS]

            DMA_CONTROL_REG |= DMA_HW | DMA_WORD; // set HW and WORD
            DMA_CONTROL_REG &= ~(DMA_BYTE | DMA_GO); // clear BYTE and GO






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 1 hour ago









            Arkku

            28.4k44663




            28.4k44663




















                up vote
                0
                down vote













                You should make sure to initialize the bits to a known default value when you declare the variable to store their values. In C, when you declare a variable you are just reserving a block of memory at a address and the size of the block is based its type. If you don't initialize the variable you can encounter undefined / unexpected behavior since the value of the variable will be effected by whatever the value / state of the memory in that block was before you declared it. By initializing the variable to a default value, you are clearing this block of memory of its existing state and putting it in a know state.



                As far as readability, you should use a bit field to store the values of the bit. A bit field enables you to store the values of the bits in a struct. This makes it easier to organize since you can use dot notation. Also, you should make sure to comment the declaration of the bit field to explain what the different fields are used for as a best practice. I hope this answers your question. Good luck with you C programming!






                share|improve this answer




















                • Bit fields are extremely non-portable. Any compiler can do what it wants. Per 6.7.2.1 Structure and union specifiers, paragraph 11 of the C standard: "... whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified."
                  – Andrew Henle
                  50 mins ago















                up vote
                0
                down vote













                You should make sure to initialize the bits to a known default value when you declare the variable to store their values. In C, when you declare a variable you are just reserving a block of memory at a address and the size of the block is based its type. If you don't initialize the variable you can encounter undefined / unexpected behavior since the value of the variable will be effected by whatever the value / state of the memory in that block was before you declared it. By initializing the variable to a default value, you are clearing this block of memory of its existing state and putting it in a know state.



                As far as readability, you should use a bit field to store the values of the bit. A bit field enables you to store the values of the bits in a struct. This makes it easier to organize since you can use dot notation. Also, you should make sure to comment the declaration of the bit field to explain what the different fields are used for as a best practice. I hope this answers your question. Good luck with you C programming!






                share|improve this answer




















                • Bit fields are extremely non-portable. Any compiler can do what it wants. Per 6.7.2.1 Structure and union specifiers, paragraph 11 of the C standard: "... whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified."
                  – Andrew Henle
                  50 mins ago













                up vote
                0
                down vote










                up vote
                0
                down vote









                You should make sure to initialize the bits to a known default value when you declare the variable to store their values. In C, when you declare a variable you are just reserving a block of memory at a address and the size of the block is based its type. If you don't initialize the variable you can encounter undefined / unexpected behavior since the value of the variable will be effected by whatever the value / state of the memory in that block was before you declared it. By initializing the variable to a default value, you are clearing this block of memory of its existing state and putting it in a know state.



                As far as readability, you should use a bit field to store the values of the bit. A bit field enables you to store the values of the bits in a struct. This makes it easier to organize since you can use dot notation. Also, you should make sure to comment the declaration of the bit field to explain what the different fields are used for as a best practice. I hope this answers your question. Good luck with you C programming!






                share|improve this answer












                You should make sure to initialize the bits to a known default value when you declare the variable to store their values. In C, when you declare a variable you are just reserving a block of memory at a address and the size of the block is based its type. If you don't initialize the variable you can encounter undefined / unexpected behavior since the value of the variable will be effected by whatever the value / state of the memory in that block was before you declared it. By initializing the variable to a default value, you are clearing this block of memory of its existing state and putting it in a know state.



                As far as readability, you should use a bit field to store the values of the bit. A bit field enables you to store the values of the bits in a struct. This makes it easier to organize since you can use dot notation. Also, you should make sure to comment the declaration of the bit field to explain what the different fields are used for as a best practice. I hope this answers your question. Good luck with you C programming!







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 1 hour ago









                Clay Raynor

                824




                824











                • Bit fields are extremely non-portable. Any compiler can do what it wants. Per 6.7.2.1 Structure and union specifiers, paragraph 11 of the C standard: "... whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified."
                  – Andrew Henle
                  50 mins ago

















                • Bit fields are extremely non-portable. Any compiler can do what it wants. Per 6.7.2.1 Structure and union specifiers, paragraph 11 of the C standard: "... whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified."
                  – Andrew Henle
                  50 mins ago
















                Bit fields are extremely non-portable. Any compiler can do what it wants. Per 6.7.2.1 Structure and union specifiers, paragraph 11 of the C standard: "... whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified."
                – Andrew Henle
                50 mins ago





                Bit fields are extremely non-portable. Any compiler can do what it wants. Per 6.7.2.1 Structure and union specifiers, paragraph 11 of the C standard: "... whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified."
                – Andrew Henle
                50 mins ago











                up vote
                0
                down vote













                There is no standard for bit fields. Mapping and bit operation are dependent on compiler in this case. Binary values such as 0b0000 are not standardized also. Usual way to do is defining hexadecimal values for each bit. For example:



                #define BYTE (0x01)
                #define HW (0x02)
                /*etc*/


                When you want to set bits, you can use:



                DMA_base_ptr[DMA_CONTROL_OFFS] |= HW;


                Or you can clear bits with:



                DMA_base_ptr[DMA_CONTROL_OFFS] &= ~HW;





                share|improve this answer








                New contributor




                kurtfu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                Check out our Code of Conduct.





















                  up vote
                  0
                  down vote













                  There is no standard for bit fields. Mapping and bit operation are dependent on compiler in this case. Binary values such as 0b0000 are not standardized also. Usual way to do is defining hexadecimal values for each bit. For example:



                  #define BYTE (0x01)
                  #define HW (0x02)
                  /*etc*/


                  When you want to set bits, you can use:



                  DMA_base_ptr[DMA_CONTROL_OFFS] |= HW;


                  Or you can clear bits with:



                  DMA_base_ptr[DMA_CONTROL_OFFS] &= ~HW;





                  share|improve this answer








                  New contributor




                  kurtfu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.



















                    up vote
                    0
                    down vote










                    up vote
                    0
                    down vote









                    There is no standard for bit fields. Mapping and bit operation are dependent on compiler in this case. Binary values such as 0b0000 are not standardized also. Usual way to do is defining hexadecimal values for each bit. For example:



                    #define BYTE (0x01)
                    #define HW (0x02)
                    /*etc*/


                    When you want to set bits, you can use:



                    DMA_base_ptr[DMA_CONTROL_OFFS] |= HW;


                    Or you can clear bits with:



                    DMA_base_ptr[DMA_CONTROL_OFFS] &= ~HW;





                    share|improve this answer








                    New contributor




                    kurtfu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                    Check out our Code of Conduct.









                    There is no standard for bit fields. Mapping and bit operation are dependent on compiler in this case. Binary values such as 0b0000 are not standardized also. Usual way to do is defining hexadecimal values for each bit. For example:



                    #define BYTE (0x01)
                    #define HW (0x02)
                    /*etc*/


                    When you want to set bits, you can use:



                    DMA_base_ptr[DMA_CONTROL_OFFS] |= HW;


                    Or you can clear bits with:



                    DMA_base_ptr[DMA_CONTROL_OFFS] &= ~HW;






                    share|improve this answer








                    New contributor




                    kurtfu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                    Check out our Code of Conduct.









                    share|improve this answer



                    share|improve this answer






                    New contributor




                    kurtfu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                    Check out our Code of Conduct.









                    answered 1 hour ago









                    kurtfu

                    11




                    11




                    New contributor




                    kurtfu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                    Check out our Code of Conduct.





                    New contributor





                    kurtfu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                    Check out our Code of Conduct.






                    kurtfu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                    Check out our Code of Conduct.




















                        up vote
                        0
                        down vote













                        Modern C compilers handle trivial inline functions just fine – without overhead. I’d make all of the abstractions functions, so that the user doesn’t need to manipulate any bits or integers, and is unlikely to abuse the implementation details.



                        You can of course use constants and not functions for implementation details, but the API should be functions. This also allows using macros instead of functions if you’re using an ancient compiler.



                        For example:



                        #include <stdbool.h>
                        #include <stdint.h>

                        typedef union DmaBase
                        volatile uint8_t u8[32];
                        DmaBase;
                        static inline DmaBase *const dma1__base(void) return (void*)0x12340000;

                        // instead of DMA_CONTROL_OFFS
                        static inline volatile uint8_t *dma_CONTROL(DmaBase *base) return &(base->u8[12]);
                        // instead of constants etc
                        static inline uint8_t dma__BYTE(void) return 0x01;

                        inline bool dma_BYTE(DmaBase *base) return *dma_CONTROL(base) & dma__BYTE();
                        inline void dma_set_BYTE(DmaBase *base, bool val)
                        if (val) *dma_CONTROL(base)
                        inline bool dma1_BYTE(void) return dma_BYTE(dma1__base());
                        inline void dma1_set_BYTE(bool val) dma_set_BYTE(dma1__base(), val);





                        share|improve this answer
























                          up vote
                          0
                          down vote













                          Modern C compilers handle trivial inline functions just fine – without overhead. I’d make all of the abstractions functions, so that the user doesn’t need to manipulate any bits or integers, and is unlikely to abuse the implementation details.



                          You can of course use constants and not functions for implementation details, but the API should be functions. This also allows using macros instead of functions if you’re using an ancient compiler.



                          For example:



                          #include <stdbool.h>
                          #include <stdint.h>

                          typedef union DmaBase
                          volatile uint8_t u8[32];
                          DmaBase;
                          static inline DmaBase *const dma1__base(void) return (void*)0x12340000;

                          // instead of DMA_CONTROL_OFFS
                          static inline volatile uint8_t *dma_CONTROL(DmaBase *base) return &(base->u8[12]);
                          // instead of constants etc
                          static inline uint8_t dma__BYTE(void) return 0x01;

                          inline bool dma_BYTE(DmaBase *base) return *dma_CONTROL(base) & dma__BYTE();
                          inline void dma_set_BYTE(DmaBase *base, bool val)
                          if (val) *dma_CONTROL(base)
                          inline bool dma1_BYTE(void) return dma_BYTE(dma1__base());
                          inline void dma1_set_BYTE(bool val) dma_set_BYTE(dma1__base(), val);





                          share|improve this answer






















                            up vote
                            0
                            down vote










                            up vote
                            0
                            down vote









                            Modern C compilers handle trivial inline functions just fine – without overhead. I’d make all of the abstractions functions, so that the user doesn’t need to manipulate any bits or integers, and is unlikely to abuse the implementation details.



                            You can of course use constants and not functions for implementation details, but the API should be functions. This also allows using macros instead of functions if you’re using an ancient compiler.



                            For example:



                            #include <stdbool.h>
                            #include <stdint.h>

                            typedef union DmaBase
                            volatile uint8_t u8[32];
                            DmaBase;
                            static inline DmaBase *const dma1__base(void) return (void*)0x12340000;

                            // instead of DMA_CONTROL_OFFS
                            static inline volatile uint8_t *dma_CONTROL(DmaBase *base) return &(base->u8[12]);
                            // instead of constants etc
                            static inline uint8_t dma__BYTE(void) return 0x01;

                            inline bool dma_BYTE(DmaBase *base) return *dma_CONTROL(base) & dma__BYTE();
                            inline void dma_set_BYTE(DmaBase *base, bool val)
                            if (val) *dma_CONTROL(base)
                            inline bool dma1_BYTE(void) return dma_BYTE(dma1__base());
                            inline void dma1_set_BYTE(bool val) dma_set_BYTE(dma1__base(), val);





                            share|improve this answer












                            Modern C compilers handle trivial inline functions just fine – without overhead. I’d make all of the abstractions functions, so that the user doesn’t need to manipulate any bits or integers, and is unlikely to abuse the implementation details.



                            You can of course use constants and not functions for implementation details, but the API should be functions. This also allows using macros instead of functions if you’re using an ancient compiler.



                            For example:



                            #include <stdbool.h>
                            #include <stdint.h>

                            typedef union DmaBase
                            volatile uint8_t u8[32];
                            DmaBase;
                            static inline DmaBase *const dma1__base(void) return (void*)0x12340000;

                            // instead of DMA_CONTROL_OFFS
                            static inline volatile uint8_t *dma_CONTROL(DmaBase *base) return &(base->u8[12]);
                            // instead of constants etc
                            static inline uint8_t dma__BYTE(void) return 0x01;

                            inline bool dma_BYTE(DmaBase *base) return *dma_CONTROL(base) & dma__BYTE();
                            inline void dma_set_BYTE(DmaBase *base, bool val)
                            if (val) *dma_CONTROL(base)
                            inline bool dma1_BYTE(void) return dma_BYTE(dma1__base());
                            inline void dma1_set_BYTE(bool val) dma_set_BYTE(dma1__base(), val);






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered 31 mins ago









                            Kuba Ober

                            68.1k980179




                            68.1k980179




















                                KateOleneva is a new contributor. Be nice, and check out our Code of Conduct.









                                 

                                draft saved


                                draft discarded


















                                KateOleneva is a new contributor. Be nice, and check out our Code of Conduct.












                                KateOleneva is a new contributor. Be nice, and check out our Code of Conduct.











                                KateOleneva is a new contributor. Be nice, and check out our Code of Conduct.













                                 


                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function ()
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53118858%2fbit-manipulations-good-practices%23new-answer', 'question_page');

                                );

                                Post as a guest













































































                                Comments

                                Popular posts from this blog

                                Long meetings (6-7 hours a day): Being “babysat” by supervisor

                                Is the Concept of Multiple Fantasy Races Scientifically Flawed? [closed]

                                Confectionery