STDIO Bài viết là một trong những ứng dụng khi học các phép toán trên bit. Sử dụng các phép toán trên bit sẽ làm cho việc tính toán diễn ra nhanh hơn, hơn thế nữa các phép toán trên bit sẽ thể hiện sự vượt trội của mình về tính toán trong của thế giới đồ họa.
Nội dung bài viết

Giới thiệu

Bài viết sẽ mang lại cảm hứng đến cho bạn đọc bởi vì bài viết này không giống như các bài giảng trên trường mà bạn đọc thường học. Ví dụ như các bài giảng nhàm chán: dịch sang trái/phải 1 bit là nhân/chia cho 2 và đúc kết được công thức dịch sang trái/phải là nhân/chia cho 2 lũy thừa n.

Tiền đề bài viết

Nội dung bài viết là một trong những bài học của khóa lập trình nền tảng tại STDIO Training và là kiến thức để áp dụng cho những thứ rất hay tôi lấy ví dụ như: xử lý và hiện thị ngôn ngữ trong bảng chat của một ứng dụng hay một trò chơi, các phương pháp nén của các loại ảnh, ...

Đọc một tệp tin văn bản và hiển trị văn bản dưới dạng nhị phân

Bài viết liên quan: Đọc ghi file

Tôi dùng Notepad++ tạo một tệp tin đặt tên là input.stdio với nội dung là chuỗi "STDIO" và một số setup để thuận tiện cho việc học: với 5 ký tự là "STDIO" thì tệp tin này đang chứa 5 bytes

1


2

Các bước in chuỗi bit

Tôi có một chuỗi bit có độ dài là 8: 1101 0101

Tôi muốn lấy bit 1 ở ví trí thứ 1 thì tôi sẽ xem xét xem đằng sau nó có bao nhiêu bit tôi sẽ dịch sang phải bấy nhiêu bit

1101 0101 >> 6 = 0000 0011

Với mã hexa 0x1 = 1 mà chúng ta đã biết giống như số thập phân 1.1 = 1.1000... và 1 = ...0001 

Kết quả mới ở trên tôi dùng phép toán AND, chỉ cần lấy bit cuối ra là hoàn thành bài toán

  0000 0011
&       0x1
= 0000 0001

Phép toán trên được hiểu như sau

  0000 0011 
& 0000 0001 
= 0000 0001

Lưu ý: Đôi khi 1101 0101 >> 6 = 1111 1111. Lưu ý này sẽ rất hữu ích với các bạn sắp triển khai mã C để nén, xử lý ảnh.

Hiện thực

Tải tệp tin input.stdio tại đây

Tôi tạo một tệp tin main.c và bắt đầu khai báo đoạn mã in ra mã nhị phân của riêng một ký tự

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

FILE *file       = NULL;
char *data 		 = NULL;
size_t size      = 0;
const char *name = "input.stdio";

void printBinary(void *symbol, int length)
{
    for(int i = length - 1; i >= 0; i--)
    {
        printf("%d", (*(char *)symbol >> i) & 0x1);
    }
    printf("\n");
}
  • Vì muốn lấy giá trị tại địa chỉ mà con trỏ void trỏ đến nên tôi phải ép kiểu và tôi chọn một kiểu: char *.
  • Bạn đọc có thể thay thế kiểu khác như: unsigned *, int *, long *, ... miễn là một kiểu gì đó liên quan đến số nguyên. (Tham khảo tại đây)
  • Cuối cùng lấy giá trị ở nơi mà con trỏ symbol trỏ đến bằng toán tử *

Tổng quát: *(char *)symbol.

Tôi tạo một hàm để in tất cả các ký tự dưới dạng nhị phân

void printAll()
{
	for(size_t i = 0; i < size; i++)
	{
		printBinary(data + i, sizeof(char) * 8); 
        printf("\n");
	}
}

Hàm sizeof trả về số lượng byte của một mục tiêu nào đó. Với: 1 byte = 8 bit

Đoạn mã sau đây đã được đề cập trong bài của tác giả Nguyễn Minh Hiếu

void getSize()
{
	file = fopen(name, "rb");
	if(!file) 
	{
		perror("Input file error: ");
	}
	else 
	{
		fseek(file, 0, SEEK_END);
		size = ftell(file);
		fseek(file, 0, SEEK_SET);
		fclose(file);
	}
}

void alloc()
{
	data = (char *)calloc(size, sizeof(char));
	if(!data)
	{
		perror("Alloc data fail: ");
	}
}

void read()
{
	file = fopen(name, "rb");
	if(!file) 
	{
		perror("Input file error: ");
	}
	else 
	{
		fread(data, 1, size, file);
		fclose(file);
	}	
}

void release()
{
	if(data)
	{
		free(data);
		data = NULL;	
	}
}

Trình tự gọi hàm sẽ là: 

  1. Lấy kích thước của tệp tin dữ liệu
  2. Cấp phát vùng nhớ
  3. Đọc dữ liệu từ tệp tin dữ liệu
  4. In tất cả dữ liệu dưới dạng nhị phân
  5. Giải phóng vùng nhớ

Mã nguồn đầy đủ

Tải mã nguồn đầy đủ tại đây

 

THẢO LUẬN
ĐÓNG