

C语言陷阱与技巧第13节,1字节(Byte)一定等于8位(bit)吗?C语言怎么操作位?
source link: https://blog.popkx.com/c-language-traps-and-skills-section-13-does-byte-necessarily-equal-8-bits-how-does-c-operate-bits/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C语言陷阱与技巧第13节,1字节(Byte)一定等于8位(bit)吗?C语言怎么操作位?
C语言没有类似于 Java 的“垃圾回收”等高级编程语言特性,也不像 python 那样无需显示声明类型就能使用变量,因此在很多人看来,C语言有些“低级”。但是C语言的这些“低级”也是 C语言的优点——使用C语言开发程序,程序员能够准确知道究竟使用了多少资源,以及哪些资源还在内存里,哪些已经被释放。换句话说,C语言程序具备资源的使用确定性。
因此,C语言特别适合用于一些资源比较匮乏的项目开发中。在这些项目中,以嵌入式项目为代表,一般都需要严格控制内存的使用——使用 1 个字节(Byte)就能存放的值,绝对不定义 2 个字节宽度的变量。甚至,一些“抠门”的C语言程序员会将 1 个字节掰成若干个位(bit)使用。
所以,在C语言程序开发中,常常需要操作某个变量特定的位(bit),这对于C语言来说当然没有任何难度,各种移位操作就能够方便的解决该类需求,例如:
unsigned char status;
status |= 0x01 << 2;
status &= ~0x01;
上面第二行C语言代码将 status 的第3个位(bit 2)设置为 1,第三行C语言代码将 status 的第1个位(bit 0)设置为 0。可以看出,借助于位运算,C语言可以比较简单的操作 status 的指定位。不过,C语言这种操作位的方法有时候看起来不够直观——至少没有直接赋值那么直观。
那C语言有没有更加直观的位操作方法呢?
上面的例子通过移位、以及或与非等操作实现对变量 status 的位操作,但是看起来却不是那么直观,那么C语言有没有更加直观的位操作方法呢?似乎可以借助C语言的联合体(union)和位域(bit field)语法,间接的实现位操作,请看下面的C语言代码:
union convert{
unsigned char status;
struct __bits {
unsigned char bit0:1;
unsigned char bit1:1;
unsigned char bit2:1;
unsigned char bit3:1;
unsigned char bit4:1;
unsigned char bit5:1;
unsigned char bit6:1;
unsigned char bit7:1;
}v;
};
此例中 status 和 bits 结构体共享一个字节的内存空间,结构体 bits 利用C言中的位域语法将一个字节的内存空间拆分成 8 个位,这种情况下,要读写 status 的位就非常简单了,请看下面的C语言示例代码:
union convert cv;
// 写 status 的 bit 3
cv.v.bit3 = 0;
// 写 status 的 bit 7
cv.v.bit7 = 1;
// 读 status 的 bit 5
r = cv.v.bit5;
编写 main() 函数,测试通过位域操作 status 的位,相关C语言代码如下,请看:
int main()
{
union convert cv;
cv.status = 0;
cv.v.bit3 = 1;
cv.v.bit1 = 1;
printf("%d\n", cv.status);
return 0;
}
main() 函数一开始将 status 置为 0,然后将它的 bit1 和 bit3 设置为 1,也就相当于将 status 设置为 0x0a,编译并执行这段C语言代码,得到如下输出:
# gcc t.c
# ./a.out
10
一切与预期一致,这样就实现了以“赋值”的形式,操作C语言中的位,而且看起来比“移位与或非操作”更加直观,所以这样的操作更好了?
事实上,有一些C语言程序员的确这么用,至少我的一些同事喜欢这样的位操作。
警惕“常识陷阱”
1 个字节(Byte)等于 8 个位(bit)似乎已经是程序员间的常识了,很少有人质疑这一点。但是作为C语言程序员,我们常常要在不同的硬件平台上做底层开发,应该明白:1个字节等于8个位只是惯例而已,C标准并没有定义这一点。有些编译器并不遵守这个惯例,例如,在 Texas 的 C55x DSP 的平台上,1 个字节等于 16 个位。在这个平台上,各种数据类型占用的位数有些奇怪:
以 long long 为例,在该平台上 long long 之所以等于 40 bit,而不是我们常用的 64 bit,是因为它们的 ALU 是 40 bit 宽,因此编译器规定 long long 为 40 bit 可以降低功耗和提升效率。
另外, 就算在 1 个字节等于 8 个位的硬件平台上,单个字节的 8 个位是如何分布的也是没有明确标准的。
阅读更多: C语言
Recommend
-
15
头文件是C语言的一个重要组成部分,这种类型的文件名一般以 .h 结尾,h 表示 header,因此被称为“头文件”。头文件里一般存放公开的函数原型,数据类型等内容,其他模块需要使用这些函数或者数据类型时,只需包含相应头文件即可。相信读者大都使用过C语言...
-
10
上一节讨论了C语言的 union 语法的一个使用场景,读者应该发现,union 成员共享一块内存的特性使得C语言程序员能够写出更加节约资源的程序。不过也有读者在看了上一节文章后,评论或者私信说了一些关于C语言 union 的特性,这些回复有些是不严谨的。如果...
-
20
C语言陷阱与技巧第33节,联合体union的使用场景是什么?它能解决什么问题?为什么要使用union语法? ...
-
15
在C语言程序开发中,遇到复杂问题需要描述时,最常使用的就是结构体了。事实上,如果某个函数的参数比较多,并且这些参数被使用的频率比较高,为了C语言代码的简洁,也常将这些参数封装为结构体。“重复的C语言代码”如果函数的参数比较多,很容...
-
26
在C语言程序开发中,一些比较成熟的库函数常常会被使用。毕竟,如果手边就有不错的“轮子”可以用,没有程序员愿意再花费精力凭空造一个轮子出来。奇怪的 void* 指针事实上,C语言标准库提供了非常丰富的成熟函数供程序员使用,不过不知道读者注...
-
11
前面的文章曾讨论,为了写出适应性更广的C语言程序,程序员考虑问题时应面面俱到。例如,在C语言程序中调用 open() 函数尝试打开文件时,应考虑到文件是否存在,当前程序是否有足够权限等情况。在打开文件失败时,需要做相应的错误处理,这样才能让程序的稳定性...
-
13
C语言陷阱与技巧第29节,很多程序员不知道,C语言也能“继承”父类 发表于 201...
-
8
在各种编程语言中,字符串的处理都是非常重要,也是非常频繁的需求。但是在C语言中,很多编译器为了保持C语言程序的高效率和低消耗,通常都不会提供边界检查等安全保障,所以,程序员一不小心就可能写出不安全的C语言代码,本文主要讨论一种常见的安全隐患。
-
16
上一节讨论了结合指针和结构体语法,C语言也能实现“面向对象”编程。由此可以看出C语言是一门极其灵活的语言,简洁的语法即可实现复杂的程序。C语言“对象”的成员变量不过,在面向对象编程中,对象不仅仅有成员函数,也应该有成员变量。成员变量...
-
10
C语言中的结构体是非常有用的复合数据类型,正是有了结构体,C语言在描述复杂问题时才能够得心应手。事实上,当初 Dennis Ritchie 开发C语言用于替换 B 语言,其中一个主要原因就是 B 语言不支持“结构体”式数据结构。C语言中的结构体非常有用例...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK