My c practices (2): The combination of good uses

Source: Internet
Author: User

In C, the Union type is a special type. Multiple members share a storage area (the maximum member length) and can only contain one member value at a time, memory alignment is performed. The sizeof operation on the Union type includes the amount of storage space required by all members, as well as the space filled between members and after members. Union is similar to the "variant record" in other languages. If the Union has a large length or a large number of concurrencies, it can greatly save storage space.
1. A union can only assign a value to one member at a time and use it. However, the C language does not provide a method to query the members used for the last assignment. We can define an Enum, in which each enumeration constant represents the identifier of each member of the Union. Then, the Union and the enum are encapsulated in a struct. When assigning values to a member of the Union, the corresponding flag is set. In this way, the Union member assignment can be tracked.

/* Widget. c: Use enumeration constants to track the assignment of Members of the Union type */<br/> # include <stdio. h> <br/> # include <string. h> <br/> Enum widget_tag {/* sign of each member associated */<br/> count_widget, <br/> value_widget, <br/> name_widget <br/>}; <br/> struct widget {/* encapsulate union and enum in a struct */<br/> Enum widget_tag tag; <br/> Union {<br/> long count; <br/> double value; <br/> char name [10]; <br/>} data; <br/>} X; <br/> typedef struct widget; <br/>/* call this function and you do not need to consider the union member used for the previous assignment */<br/> void print_widget (widget W) {<br/> switch (W. tag) {<br/> case count_widget: <br/> printf ("count: % LD/N", W. data. count); <br/> break; <br/> case value_widget: <br/> printf ("value: %. 15f/N ", W. data. value); <br/> break; <br/> case name_widget: <br/> printf ("Name:/" % S/"/N", W. data. name); <br/> break; <br/>}< br/> int main () {<br/> X. tag = count_widget;/* to assign a value to the member count, set its flag */<br/> X. data. count = 10000; <br/> print_widget (x);/* automatically prints the value of this Member */</P> <p> X. tag = value_widget; <br/> X. data. value = 3.14159265358979323846; <br/> print_widget (x); </P> <p> X. tag = name_widget; <br/> strncpy (X. data. name, "Millard", 10); <br/> print_widget (x); <br/> return 0; <br/>}< br/>

2. If a member of the Union is referenced, but the last value assigned to the Union is not the member, the Union is used in a non-portable manner. We can use this method to understand some underlying Data Representation Methods in the computer. For example, you need to find out how floating point numbers are represented:

# Include <stdio. h> <br/>/* use the Union type to obtain the underlying representation of the Floating Point Number */<br/> void print_rep (float F) {</P> <p> Union {/* generate a Union with floating point numbers and Integers of the same length */<br/> float a; <br/> int I; <br/>} aori; </P> <p> aori. A = f;/* assign values to floating-point number members */<br/>/* read integer Member values because they share the storage space, therefore, we can obtain the floating point memory representation */<br/> printf ("the representation of % 12.7e is % # 010x/N", aori. a, aori. i); <br/>}< br/> int main () {<br/> print_rep (16.5 ); /* get the memory representation of 16.5 */<br/> printf ("% # 010x/N", (INT) 16.5 ); /* Direct conversion, the memory representation cannot be obtained */<br/> return 0; <br/>}

The storage layout of the float type is generally 1-bit symbol bit s, 8-bit index E, and 23-bit ending number. Convert to value v = (-1) ^ s * 1. M * 2 ^ (E-127 ). For example, if 16.5 = 00010000.1 = 1.00001*2 ^ 4, the symbol bit is 0, the index bit is 4 + 127 = 131 = 10000011, And the ending number is 00001000000000000000000. After splicing, the system generates a memory representation of 16.5, the result is consistent with that in the code. Note that this method may not be completely portable. If you convert a floating point number to an integer directly, you cannot find the underlying representation, because (INT) 16.5 will cut off the tail and convert it to an integer 16.
However, we can use Indirect transformation to obtain the underlying representation of floating point numbers, for exampleAddress Transformation
(Only transform the memory address of the object without transforming the content in the object memory), using address transformation is a common method to obtain memory representation of any type of object. Here, the address of the floating point variable is converted to the unsigned char * pointer C, which stores the starting address of the floating point variable, that is, * C contains the low byte content of F, * (C + 1 )~ * (C + 3) is the content of other bytes. Note that * (C + I) is equivalent to C [I], so * (C + I) it can also be changed to C [I].

# Include <stdio. h> <br/>/* use type conversion to obtain the underlying representation of a floating point */<br/> int main () {<br/> float F = 16.5; <br/> int I = 0; <br/>/* C: memory start address for storing F, * C contains the low byte content of f */<br/> unsigned char * c = (unsigned char *) & F; <br/>/* print the content of F in four bytes, from the high byte to the low byte */<br/> for (I = 3; I> = 0; I --) <br/> printf ("0x % x/N", * (C + I )); /* C [I] */<br/> return 0; <br/>}

3. Different computer architectures have different byte storage sequence. One is the low-level storage method (that is, the small-end byte order), such as Intel 80x86, from right to left storage, the high-address byte stores the high integer, the word address is the rightmost (low) byte address. One is the high-end storage method (that is, the large-end byte sequence, and the TCP/IP network transmission adopts the large-end byte sequence), such as Motorola 680x0, which is stored from left to right, the high-address byte stores the low order of integers, and the word address is the leftmost (high) byte address. We can use the Union to determine the byte sequence of the computer.

# Include <stdio. h> <br/>/* determine the byte storage sequence of the computer using the Union type */<br/> Union {<br/> long Ma; <br/> char MB [sizeof (long)]; <br/>}u; <br/> int main () {<br/> U. MA = 1;/* after initialization, the low byte of MA contains 1 */</P> <p> If (U. MB [0] = 1)/* The low byte of MA overlaps with MB [0, description: stores data from right to left */<br/> printf ("addressing is right-to-left/N"); <br/> else if (U. MB [sizeof (long)-1] = 1)/* left-to-right storage */<br/> printf ("addressing is left-to-right/N "); <br/> else printf ("addressing is strange/N"); <br/> return 0; <br/>}

 

U is of the same length as long type (for example, 4 bytes). After initialization, 1 is in the low position of MA, 0 is in the high position, and MB [0] ~ The MB [3] address ranges from low to high. In the architecture from right to left, the low 1 of Ma is stored in the low address byte, so it overlaps with MB [0. In the left-to-right architecture, the low 1 of Ma is stored in the high address byte, so it overlaps with MB [3. The Byte storage order of the computer can be determined. Of course, we can also use the address transformation method to determine. As follows:

# Include <stdio. h> <br/>/* use address transformation to determine the byte storage sequence of the Computer */<br/> int main () {<br/> long F = 1; <br/>/* C stores the starting address of F memory. * C contains the low byte content of f */<br/> unsigned char * c = (unsigned char *) & F; <br/>/* If the value of * C is 1, the data is stored from right to left. If * (C + 3) is 1, it is stored from left to right */<br/> If (* c = 1) <br/> printf ("addressing is right-to-left/N "); <br/> else if (* (C + 3) = 1) <br/> printf ("addressing is left-to-right/N "); <br/> else <br/> printf ("addressing is strange/N"); </P> <p> return 0; <br/>}

The byte order of different architectures is as follows:

Processor operating system byte sorting
Alpha all little endian
HP-PA nt little endian
UNIX big endian HP-PA
Intel x86 all little endian (x86 systems are small-end bytecode systems)
Motorola 680x0 all big endian
MIPs nt little endian
MIPs UNIX big endian
PowerPC nt little endian
PowerPC non-nt big endian (PowerPC is a large-end byte sequence)
RS/6000 UNIX big endian
Four-byte host types (four-byte host)
IXP1200 ARM core all little endian

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.