I'm working on a school assignment. I am writing a program that utilizes union
s to convert a given IP address in "192.168.1.10" format into its 32-bit single value, two 16-bit values, and four 8-bit values.
I'm having trouble with implementing my struct
s and union
s appropriately, and am looking for insight on the subject. To my understanding, union
s point to the same location as the referenced struct
, but can look at specified pieces.
Any examples showing how a struct
with four 8-bit values and a union
can be used together would help. Also, any articles or books that might help me would also be appreciated.
Below is the assignment outline:
Create a program that manages an IP address. Allow the user to enter the IP address as four 8 bit unsigned integer values (just use 4 sequential CIN statements). The program should output the IP address upon the users request as any of the following. As a single 32 bit unsigned integer value, or as four 8 bit unsigned integer values, or as 32 individual bit values which can be requested as a single bit by the user (by entering an integer 0 to 31). Or as all 32 bits assigned into 2 variable sized groups (host group and network group) and outputted as 2 unsigned integer values from 1 bit to 31 bits each.
I was going to cin
to int pt1,pt2,pt3,pt4
and assign them to the IP_Adress.pt1
, .... etc.
struct IP_Adress {
unsigned int pt1 : 8;
unsigned int pt2 : 8;
unsigned int pt3 : 8;
unsigned int pt4 : 8;
};
I have not gotten anything to work appropriately yet. I think I am lacking a true understanding of the implementation of union
s.
CodePudding user response:
A union
is not a good fit for this assignment. In fact, nothing in the text you quoted even says to use a union
at all. And, a union
will not help you with the parts of the assignment that deal with "32 individual bit values" or with "32 bits assigned into 2 variable sized groups". Those parts of the assignment will require bit shifting instead. Bit shifting is the better way to solve the other parts of the assignment, as well.
That being said, if you absolutely must use a union
, you are probably looking for something more like this instead:
union IP_Adress {
uint8_t u8[4]; // four 8-bit values
uint16_t u16[2]; // two 16-bit values
uint32_t u32; // one 32-bit value
};
Except that C does not allow you to write into one union
field and then read from another. C allows that kind of type puning, but it is undefined behavior in C .
Why is type punning considered UB?
CodePudding user response:
The asker already knows that doing this can blow up in their face a number of different ways, but here's a simple example for 4 byte, 4x1 byte, and 32x1 bit.
union bad_idea
{
uint32_t ints; // 32 bit unsigned integer
uint8_t bytes[sizeof(uint32_t)]; // 4 8 bit unsigned integers
};
and then
uint32_t get_int(const bad_idea & in)
{
return in.ints;
}
uint8_t get_byte(const bad_idea & in,
size_t offset)
{
if (offset >= sizeof(uint32_t)) trap typos and idiots
{
throw std::runtime_error("invalid offset");
}
return in.bytes[offset];
}
bool get_bit(const bad_idea & in,
size_t offset)
{
if (offset >= sizeof(uint32_t)*8)
{
throw std::runtime_error("invalid offset");
}
return (in.ints >> offset) & 1; // shift the required bit to the end (in.ints >> offset)
// then mask off all of the other bits (& 1)
}
Things get a bit ugly getting input because you can't simply
std::cin >> bad.bytes[0];
because it reads a single character. Type in 127 for the first octet and you'll wind up filling bad.bytes[0]
through bad.bytes[2]
with '1'
, '2'
, and '7'
.
You need to involve a temporary variable
int temp;
std::cin >> temp;
// tests for valid range in temp
bad.bytes[0] = temp
or risk some explosive batsmurf like
std::cin >> *(int*)&bad.bytes[0];
// tests for valid value in bad.bytes[0] impossible because aliasing has been broken
// and everything is already <expletive deleted>ed
pardon my C. The more respectable
std::cin >> *reinterpret_cast<int*>(&bad.bytes[0]);
isn't any better. As ugly as it is, use the temporary variable and bundle it up in a function to eliminate the duplication. Frankly this is a time when I'd probably fall back into C and pull out good ol' scanf
.