it Masking in C

Jinku Hu Feb 02, 2024
  1. Use the struct Keyword to Define Bitmask Data in C
  2. Use struct Combined With union to Define Bitmask Data in C
it Masking in C

This article will demonstrate multiple methods about how to use bit masking in C.

Use the struct Keyword to Define Bitmask Data in C

Bitmasks are usually used for bitwise operations to access or set individual sections of the bit field style data structures. On the other hand, Bit fields are utilized to store data efficiently and reduce the memory footprint.

Bitwise operations are also relatively faster to execute in hardware rather than common arithmetic operations. In the following example, we demonstrate the bit field’s implementation using the struct keyword.

Note that this is a special notation to construct the object where the given bit regions can be retrieved using the conventional member access operator. Bitfield structure stores a single unsigned integer occupying 32 bits in memory, but it can also be accessed in 3 different sections of size - 23-bit, 5-bit, and 4-bit values named as year, day and month respectively. As a result, the Bitfield represents the abstraction of date implemented efficiently in the memory.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

struct {
  uint32_t year : 23;
  uint32_t day : 5;
  uint32_t month : 4;
} typedef Bitfield;

int main() {
  Bitfield date = {2020, 13, 12};

  printf("sizeof Bitfield: %lu bytes\n", sizeof(date));
  printf("date: %d/%d/%d \n", date.day, date.month, date.year);

  return EXIT_SUCCESS;
}

Output:

sizeof Bitfield: 4 bytes
date: 13/12/2020

Use struct Combined With union to Define Bitmask Data in C

Alternatively, we can add the union keyword to the previous structure so that it’s possible to access the whole 32-bit number separately. Since accessing the bit-field members is slower than accessing the member of struct, we will assign the date value using the bitwise operations to the separate ydm integer member.

Note that decimal numbers representing the given date are logically OR-ed with each other, but before that, the day and month values are shifted left by 23 and 28 places, respectively. The latter numbers are taken based on the corresponding bit positions these members occupy in the bit field. Notice that each member can still be accessed separately when needed to print the output.

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

union {
    struct {
        uint32_t year:23;
        uint32_t day:5;
        uint32_t month:4;
    };
    uint32_t ydm;
} typedef BitfieldFast;

int main() {

    BitfieldFast date_f;
    date_f.ydm = 2020 | (13 << 23) | (12 << 28);

    printf("sizeof BitfieldFast: %lu bytes\n", sizeof(date_f));
    printf("date_f: %d/%d/%d \n", date_f.day, date_f.month, date_f.year);

    return EXIT_SUCCESS;
}

Output:

sizeof BitfieldFast: 4 bytes
date_f: 13/12/2020

Another typical example of bitmask usage is IP addresses in networking. Namely, IP addresses are provided with the network mask, which determines which network the given address belongs. The calculation of the network address is done by logically AND-ing the IP address and its network mask.

In this case, we defined the bit field struct to store the IP address and netmask separately. Note that logical AND-ing is done on the whole 32-bit values, but when we print the addresses as the four 8-bit sections, the member access operator is used.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

union {
  struct {
    uint8_t first : 8;
    uint8_t second : 8;
    uint8_t third : 8;
    uint8_t fourth : 8;
  };
  uint32_t ip;
} typedef IPAddress;

int main() {
  IPAddress ip1 = {10, 127, 5, 1};
  IPAddress mask = {255, 255, 240, 0};
  printf("ip1: %d.%d.%d.%d\n", ip1.first, ip1.second, ip1.third, ip1.fourth);
  ip1.ip = ip1.ip & mask.ip;
  printf("net: %d.%d.%d.%d\n", ip1.first, ip1.second, ip1.third, ip1.fourth);

  return EXIT_SUCCESS;
}

Output:

ip1: 10.127.5.1
net: 10.127.0.0
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook