Bit manipulations good practices
Clash 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:
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
New contributor
add a comment |Â
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:
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
New contributor
By the way, using0b
for base-two constants is nonstandard.
â Steve Summit
37 mins ago
add a comment |Â
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:
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
New contributor
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:
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
c standards bit
New contributor
New contributor
edited 54 mins ago
New contributor
asked 1 hour ago
KateOleneva
364
364
New contributor
New contributor
By the way, using0b
for base-two constants is nonstandard.
â Steve Summit
37 mins ago
add a comment |Â
By the way, using0b
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
add a comment |Â
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;
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
add a comment |Â
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.
Can't you just determine the bit order by referencing thestdlib.h
andstddef.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
 |Â
show 1 more comment
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
add a comment |Â
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!
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
add a comment |Â
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;
New contributor
add a comment |Â
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);
add a comment |Â
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;
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
add a comment |Â
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;
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
add a comment |Â
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;
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;
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
add a comment |Â
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
add a comment |Â
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.
Can't you just determine the bit order by referencing thestdlib.h
andstddef.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
 |Â
show 1 more comment
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.
Can't you just determine the bit order by referencing thestdlib.h
andstddef.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
 |Â
show 1 more comment
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.
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.
edited 47 mins ago
answered 1 hour ago
Steve Summit
17.2k22447
17.2k22447
Can't you just determine the bit order by referencing thestdlib.h
andstddef.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
 |Â
show 1 more comment
Can't you just determine the bit order by referencing thestdlib.h
andstddef.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
 |Â
show 1 more comment
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
add a comment |Â
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
add a comment |Â
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
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
answered 1 hour ago
Arkku
28.4k44663
28.4k44663
add a comment |Â
add a comment |Â
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!
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
add a comment |Â
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!
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
add a comment |Â
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!
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!
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
add a comment |Â
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
add a comment |Â
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;
New contributor
add a comment |Â
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;
New contributor
add a comment |Â
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;
New contributor
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;
New contributor
New contributor
answered 1 hour ago
kurtfu
11
11
New contributor
New contributor
add a comment |Â
add a comment |Â
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);
add a comment |Â
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);
add a comment |Â
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);
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);
answered 31 mins ago
Kuba Ober
68.1k980179
68.1k980179
add a comment |Â
add a comment |Â
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.
KateOleneva is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
By the way, using
0b
for base-two constants is nonstandard.â Steve Summit
37 mins ago