16 C 语言布尔类型与 sizeof 运算符详解:布尔类型的三种声明方式、执行时间、赋值规则

1 布尔类型

1.1 布尔类型概述

        布尔类型用于表示逻辑上的真(true)和假(false)两种状态,是编程中条件判断和逻辑运算的基础。在 C 语言中,布尔值的表示方式随着标准的发展而不断完善。

1.2 布尔类型的三种声明方式

宏定义方式(C89 及以前版本)

  • 在 C89 及以前的 C 语言标准中,没有原生的布尔类型。
  • 开发者通常使用宏定义来模拟布尔类型,将 TRUE FALSE 分别定义为 10
  • 这种方式不够直观,但能在一定程度上满足布尔逻辑的需求。
#include <stdio.h>// 宏定义布尔类型
#define BOOL int
#define TRUE 1
#define FALSE 0int main()
{BOOL isPass = FALSE; // 初始化为假BOOL isOk = TRUE;    // 初始化为真printf("isPass=%d, isOk=%d\n", isPass, isOk); // 输出: isPass=0, isOk=1if (isPass){printf("不会执行\n"); // 条件不满足,不会执行}if (isOk){printf("会执行\n"); // 条件满足,会执行}return 0;
}

        程序在 VS Code 中的运行结果如下所示:

_Bool 类型(C99 标准引入)

  • C99 标准引入了原生的布尔类型 _Bool
  • _Bool 类型只能存储 0 或 1,任何非 0 值赋给 _Bool 变量都会被隐式转换为 1(真)
  • 这种方式比宏定义更规范,但代码可读性稍差,因为通常需要输出为整数形式。
#include <stdio.h>int main()
{_Bool isPass = 0;   // 初始化为假// _Bool isOk = 1;  // 初始化为真_Bool isOk = -4;    // 非 0 值被转换为 1(真)printf("isPass=%d, isOk=%d\n", isPass, isOk); // 输出: isPass=0, isOk=1if (isPass){printf("不会执行\n"); // 条件不满足,不会执行}if (isOk){printf("会执行\n"); // 条件满足,会执行}return 0;
}

        程序在 VS Code 中的运行结果如下所示:

bool 类型(通过 stdbool.h 头文件)

  • C99 标准还提供了 <stdbool.h> 头文件其中定义了 bool 类型作为 _Bool 的别名
  • 同时定义了 true 和 false 宏,分别表示 1 和 0,使得代码更加直观易读。
  • 这是现代 C 编程中推荐使用的布尔类型表示方式。
#include <stdio.h>
#include <stdbool.h> // 包含布尔类型定义int main()
{bool isPass = false; // 初始化为假bool isOk = true;    // 初始化为真printf("isPass=%d, isOk=%d\n", isPass, isOk); // 输出: isPass=0, isOk=1if (isPass){printf("不会执行\n"); // 条件不满足,不会执行}if (isOk){printf("会执行\n"); // 条件满足,会执行}return 0;
}

        程序在 VS Code 中的运行结果如下所示:

        我们可以通过 VS Code 查看 <stdbool.h> 的源代码。将鼠标放在 stdbool.h 或 true 或 false 上,按住 Ctrl 键并点击鼠标左键即可查看其实现。<stdbool.h> 的源代码片段通常如下:

        这进一步验证了 bool 是 _Bool 的别名,true 和 false 分别对应 1 和 0。 

1.3 三种声明方式的执行时间

宏定义方式

  • 执行时间:
    • 宏定义是在预处理阶段执行的。预处理器会在编译之前处理所有的宏定义、文件包含等指令。
    • 在预处理阶段,所有的宏定义会被替换为对应的文本。例如,BOOL 会被替换为 int,TRUE 会被替换为 1,FALSE 会被替换为 0。
  • 特点:
    • 宏定义不会引入新的类型,只是简单的文本替换。
    • 由于是在预处理阶段完成,因此在编译阶段,编译器看到的已经是替换后的代码。

_Bool 类型

  • 执行时间:
    • _Bool 类型的处理是在编译阶段完成的
    • 编译器会识别 _Bool 类型,并在生成目标代码时进行相应的处理。
  • 特点:
    • _Bool 是 C 语言原生的布尔类型,提供了更好的类型安全性。
    • 编译器会在编译阶段对 _Bool 类型的变量进行优化,确保其只存储 0 或 1。

bool 类型

  • 执行时间:
    • bool 类型的处理也是在编译阶段完成的
    • 当包含 <stdbool.h> 头文件时,预处理器会将 bool 替换为 _Bool,true 替换为 1,false 替换为 0。
    • 编译器在编译阶段会识别 _Bool 类型,并进行相应的处理。
  • 特点:
    • bool 是 _Bool 的别名,提供了更直观和可读的布尔类型定义。
    • 使用 <stdbool.h> 是现代 C 编程中推荐的方式,因为它提高了代码的可读性和一致性。

执行时间总结

方式处理阶段特点
宏定义预处理阶段简单文本替换,无类型检查,灵活性高但安全性低
_Bool 类型编译阶段原生布尔类型,类型安全,编译器优化
bool 类型编译阶段_Bool 的别名,通过 <stdbool.h> 提供,直观可读,推荐使用

1.4 布尔类型的赋值规则

接受任何整数值

  • 布尔变量可以接受任何整数值(如 char、short、int、long 等类型)或任何可隐式转换为整数的表达式(如算术运算、位运算、比较运算等)。
  • 赋值时,编译器会自动将值转换为 0(false)或 1(true),无需手动处理。

非零值视为 true(存储为 1)

  • 任何非零值(包括正整数、负整数、大整数、甚至超出 bool 存储范围的值)都会被视为 true,并存储为 1
  • bool 的存储大小是固定的(通常为 1 字节,即 _Bool 类型),但赋值时不会因值过大而报错或截断
  • 编译器会自动转换:
    • 无论赋值 1、42 还是 1000000,最终存储的值只能是 0 或 1。
    • 这是因为 bool 类型的本质是逻辑值,而非数值,编译器会隐式地将任何非零值转换为 1
#include <stdio.h>
#include <stdbool.h>int main()
{bool b1 = 42;      // 42 → true(存储为 1)bool b2 = -1;      // -1 → true(存储为 1)bool b3 = 1000000; // 1,000,000 → true(存储为 1)printf("b1=%d (实际存储值: %d)\n", b1, b1); // 输出: b1=1 (实际存储值: 1)printf("b2=%d (实际存储值: %d)\n", b2, b2); // 输出: b2=1 (实际存储值: 1)printf("b3=%d (实际存储值: %d)\n", b3, b3); // 输出: b3=1 (实际存储值: 1)return 0;
}

        程序在 VS Code 中的运行结果如下所示:

零值视为 false(存储为 0)

  • 只有 0 或显式的 false 会被视为 false,并存储为 0
#include <stdio.h>
#include <stdbool.h>int main()
{bool b4 = 0;     // 0 → false(存储为 0)bool b5 = false; // false → false(存储为 0)printf("b4 = %d\n", b4); // 0printf("b5 = %d\n", b5); // 0return 0;
}

        程序在 VS Code 中的运行结果如下所示:

规则总结

规则示例存储值说明
非零值 → true(1)bool b = 42;1任何非零值(包括负数、大数)
零值 → false(0)bool b = 0;0仅 0 或 false
隐式转换bool b = -1;1编译器自动处理非零值
  • bool 类型仅存储 0 或 1,赋值时会自动转换,无需担心数值大小。
  • 这一规则确保了布尔逻辑的简洁性和一致性。

2 sizeof 运算符

        sizeof 是 C 语言中的一个重要运算符,用于获取数据类型、变量、字面量或表达式的存储大小(以字节为单位)

        它返回一个 size_t 类型的无符号整数值,通常使用 %zu 格式占位符进行输出。size_t 的具体类型(如 unsigned int 或 unsigned long)由系统和编译器决定。

2.1 sizeof 运算符的基本用法

        sizeof 运算符的主要功能是计算内存占用大小,适用于以下场景:

  1. 基本数据类型:如 bool、char、short、int、long、long long、float、double、long double 等。
  2. 变量:直接作用于变量名。
  3. 字面量:直接作用于常量值。
  4. 表达式:计算表达式的存储大小。

语法形式:

  • 对于基本数据类型或表达式:sizeof 后面必须使用括号包裹,例如 sizeof(int)、sizeof(1 + 1)。
  • 对于变量或字面量:sizeof 后面的括号是可选的,例如 sizeof a 或 sizeof(a)。

2.2 sizeof 的使用场景

计算基本数据类型的大小

        基本数据类型的大小可能因编译器和平台而异。以下是常见数据类型的典型大小:

#include <stdio.h>
#include <stdbool.h> // 包含 bool 类型int main()
{// 使用转义字符 \t 格式化输出printf("数据类型\t大小(字节)\n");printf("--------\t-----------\n");// 对于基本数据类型:sizeof 必须使用括号包裹printf("bool \t\t %zu \n", sizeof(bool));              // 通常为 1 字节printf("char \t\t %zu \n", sizeof(char));              // 通常为 1 字节printf("short \t\t %zu \n", sizeof(short));            // 通常为 2 字节printf("int \t\t %zu \n", sizeof(int));                // 通常为 4 字节printf("long \t\t %zu \n", sizeof(long));              // 通常为 4 或 8 字节printf("long long \t %zu \n", sizeof(long long));      // 通常为 8 字节printf("float \t\t %zu \n", sizeof(float));            // 通常为 4 字节printf("double \t\t %zu \n", sizeof(double));          // 通常为 8 字节printf("long double:\t %zu \n", sizeof(long double)); // 通常为 16 字节return 0;
}

        程序在 VS Code 中的运行结果如下所示:

计算字面量的大小

        字面量的大小取决于其类型,sizeof 后面的括号是可选的

  • 字符字面量(如 'a'):通常被提升为 int 类型,因此 sizeof('a') 返回 4(字节)
  • 整数和浮点数字面量:大小由其类型决定。例如:
    • 431 是 int 类型,sizeof(431) 返回 4。
    • 4.31 是 double 类型,sizeof 4.31 返回 8。
#include <stdio.h>
#include <stdbool.h>int main()
{// 字符类型字面量:在 C 中字符常量如 'a' 实际上是 int 类型(通常为 4 字节)printf("字符类型字面量('a'):%zu\n", sizeof('a'));     // 输出通常为 4(bool 提升为 int)printf("布尔类型字面量(true):%zu\n", sizeof(true));   // 输出通常为 4(bool 提升为 int)printf("布尔类型字面量(false):%zu\n", sizeof(false)); // 输出通常为 4(bool 提升为 int)// 整型字面量:默认是 int 类型printf("整型字面量(431):%zu\n", sizeof(431)); // 输出通常为 4(int)// 长整型后缀 L:long int(具体大小依赖平台)printf("长整型字面量(431L):%zu\n", sizeof(431L)); // 具体大小依赖平台// 长长整型后缀 LL:long long int(通常为 8 字节)printf("长长整型字面量(431LL):%zu\n", sizeof(431LL)); // 输出通常为 8(long long)// 单精度浮点数字面量:使用 f 后缀表示 float(通常为 4 字节)printf("单精度浮点型字面量(4.31f):%zu\n", sizeof(4.31f)); // 输出通常为 4(float)// 双精度浮点数字面量:默认是 double 类型(通常为 8 字节)printf("双精度浮点型字面量(4.31):%zu\n", sizeof(4.31)); // 输出通常为 8(double)// 长双精度浮点数字面量:使用 L 后缀表示 long double(通常为 16 字节)printf("长双精度浮点型字面量(4.31L):%zu\n", sizeof(4.31L)); // 输出通常 16// 对于字面量:sizeof 后面的括号是可选的printf("对于字面量:sizeof 后面的括号是可选的:%zu\n", sizeof true);  // 输出通常为 4(bool 提升为 int)printf("对于字面量:sizeof 后面的括号是可选的:%zu\n", sizeof 431);   // 输出通常为 4(int)printf("对于字面量:sizeof 后面的括号是可选的:%zu\n", sizeof 431L);  // 具体大小依赖平台printf("对于字面量:sizeof 后面的括号是可选的:%zu\n", sizeof 431LL); // 输出通常为 8(long long)printf("对于字面量:sizeof 后面的括号是可选的:%zu\n", sizeof 4.31f); // 输出通常为 4(float)printf("对于字面量:sizeof 后面的括号是可选的:%zu\n", sizeof 4.31);  // 输出通常为 8(double)printf("对于字面量:sizeof 后面的括号是可选的:%zu\n", sizeof 4.31L); // 输出通常为 16(long double)return 0;
}

        程序在 VS Code 中的运行结果如下所示:

计算变量的大小

        变量的大小与其类型一致,sizeof 后面的括号是可选的

#include <stdio.h>int main()
{char a = 'A';             // char 类型变量short b = 66;             // short 类型变量int c = 66;               // int 类型变量long d = 8888888L;        // long 类型变量long long e = 99999999LL; // long long 类型变量float f = 5.6f;           // float 类型变量double g = 10.8;          // double 类型变量long double h = 12.34L;   // long double 类型变量printf("a: %zu \n", sizeof(a)); // 输出为 1(char 类型)printf("b: %zu \n", sizeof(b)); // 输出为 2(short 类型)printf("c: %zu \n", sizeof(c)); // 输出为 4(int 类型)printf("d: %zu \n", sizeof(d)); // 具体大小依赖平台// 对于变量:sizeof 后面的括号是可选的printf("e: %zu \n", sizeof e); // 输出为 8(long long 类型)printf("f: %zu \n", sizeof f); // 输出为 4(float 类型)printf("g: %zu \n", sizeof g); // 输出为 8(double 类型)printf("h: %zu \n", sizeof h); // 输出为 16(long double 类型)return 0;
}

        程序在 VS Code 中的运行结果如下所示:

计算表达式的大小

        sizeof 也可以用于计算表达式的存储大小:

#include <stdio.h>int main()
{int d1 = 10;double d2 = 20.0;// printf("表达式(d1 + d2):%zu \n", sizeof d1 + d2);  // 不加括号这里输出会出问题,printf("表达式(d1 + d2)的存储大小:%zu \n", sizeof(d1 + d2)); // 加上括号当成一个整体// int 类型和 double 类型相加,结果是 double 类型,所以 sizeof(d1 + d2) 的结果是 8printf("表达式(1 + 2)的存储大小:%zu \n", sizeof(1 + 2)); // 4return 0;
}

        程序在 VS Code 中的运行结果如下所示:

2.3 注意事项

  1. 括号的可选性:
    • 对基本数据类型和表达式必须使用括号(如 sizeof(int))
    • 对变量或字面量可省略括号(如 sizeof a)
    • 建议:为了统一规范和代码可读性,建议在使用 sizeof 时,始终使用括号,无论是对数据类型、变量、字面量还是表达式。例如:sizeof(int)、sizeof(variableName)、sizeof(42)。
    类型提升:
    • 字符字面量(如 'a')在 sizeof 运算中会被提升为 int 类型
  2. 平台和编译器依赖性:
    • 数据类型的大小可能因平台和编译器而异(如 long 可能是 4 或 8 字节、long double 可能是 8 字节、10 字节、12 字节或 16 字节)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/81393.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++详解】string各种接口如何使用保姆级攻略

文章目录 一、string介绍二、string使用构造函数析构函数赋值运算符重载string的遍历修改方法1、下标[]2、迭代器3、范围for 迭代器使用详解const迭代器反向迭代器&#xff08;reverse) Capacity(容量相关)size/lengthmax_sizecapacityclear/emptyshrink_to_fit(缩容)reserve(扩…

回调函数应用示例

回调函数是一种通过函数指针&#xff08;或引用&#xff09;调用的函数&#xff0c;它在特定事件或条件发生时被另一个函数调用。回调函数的核心思想是将函数作为参数传递&#xff0c;以便在适当的时候执行自定义逻辑&#xff0c;常用于异步编程、事件驱动架构等场景。 业务场景…

linux标准库头文件解析

linuxc标准库 C 标准库&#xff08;C Standard Library&#xff09;包含了一组头文件&#xff0c;这些头文件提供了许多函数和宏&#xff0c;用于处理输入输出、字符串操作、数学计算、内存管理等常见编程任务。。 头文件功能简介<stdio.h>标准输入输出库&#xff0c;包含…

Unbuntu 命令

Ubuntu 命令速查表​ ​分类​​命令​​功能描述​​示例/常用选项​​​​文件与目录​ls列出目录内容ls -a&#xff08;显示隐藏文件&#xff09;; ls -lh&#xff08;详细列表易读大小&#xff09; cd切换目录cd ~&#xff08;主目录&#xff09;; cd ..&#xff08;上级…

怎么在excel单元格1-5行中在原来内容前面加上固定一个字?

环境&#xff1a; WPS 2024 问题描述&#xff1a; 怎么在excel单元格1-5行中在原来内容前面加上固定一个字&#xff1f; 解决方案&#xff1a; 1.在Excel中&#xff0c;如果您想在单元格的内容前面添加一个固定的字&#xff0c;可以通过以下几种方法实现&#xff1a; 方法…

Linux zip、unzip 压缩和解压

zip 命令用于压缩文件&#xff0c;压缩后的文件后缀名为 .zip 。 对应的解压命令是 unzip 。 测试用的目录结构如下&#xff0c; userzn:~/test$ tree . ├── folder1 │ ├── folder111 │ │ └── file1.txt │ └── main1.c ├── folder2 │ ├── …

【C语言练习】047. 理解递归与循环的转换

047. 理解递归与循环的转换 047. 理解递归与循环的转换1. 递归与循环的基本概念递归循环2. 递归与循环的转换示例1:计算阶乘示例2:汉诺塔问题3. 递归与循环的适用场景递归:循环:一、递归的适用场景与代码示例1. 分治问题2. 树形结构遍历3. 复杂状态问题二、循环的适用场景与…

我的创作纪念日——《惊变256天》

我的创作纪念日——《惊变256天》 机缘收获日常成就憧憬 最近&#xff0c;博主收到了 CSDN 发来的系统消息&#xff0c;这才惊觉&#xff0c;自上次第128天创作纪念日之后&#xff0c;竟又悄然走过了 128 天。站在 256 天这个颇具意义的里程碑前回望&#xff0c;博主在2023 年 …

Redis 事务与管道:原理、区别与应用实践

在现代分布式系统开发中&#xff0c;Redis 作为高性能的内存数据库&#xff0c;其事务处理和管道技术是开发者必须掌握的核心知识点。本文将深入探讨 Redis 事务和管道的实现原理、使用场景、性能差异以及最佳实践&#xff0c;帮助开发者根据实际需求选择合适的技术方案。 一、…

Mysql 8.0.32 union all 创建视图后中文模糊查询失效

记录问题,最近在使用union all聚合了三张表的数据,创建视图作为查询主表,发现字段值为中文的筛选无法生效.......... sql示例: CREATE OR REPLACE VIEW test_view AS SELECTid,name,location_address AS address,type,"1" AS data_type,COALESCE ( update_time, cr…

Spatial Transformer Layer

我们知道cnn是无法识别到经过缩放和旋转的图片的,但是这个spatial transformer这个neutral network是可以做到的,可以被放到cnn里 接下来就是讲解一个空间变换层地例子:我们可以看到,layerl就是layerl-1经过平移得到的,其中,我们layerl中的每一个元素,是上一层每一个元素与权重…

spark-standalone

一、定义&#xff1a;Standalone 模式是一种独立的集群部署模式&#xff0c;自带完整服务&#xff0c;可单独部署到一个集群中&#xff0c;无需依赖任何其他资源管理系统。 二、配置步骤 1.和前面一样拉到hadoop101的/opt/module这个目录里面。 2.压缩 3.重命名为spark-sta…

Vim编辑器命令模式操作指南

Vim 的命令模式&#xff08;即 Normal 模式&#xff09;是 Vim 的核心操作模式&#xff0c;用于执行文本编辑、导航、搜索、保存等操作。以下是命令模式下的常用操作总结&#xff1a; 1. 模式切换 进入命令模式&#xff1a;在任何模式下按 Esc 键&#xff08;可能需要多次按&a…

网络体系结构(OSI,TCP/IP)

网络体系结构 一、设计分层网络模型 简化设计&#xff1a;分层将复杂的大系统分解成小模块&#xff0c;每一层专注处理特定功能模块化&#xff1a;每一层独立&#xff0c;便于开发、调试、更新和维护互操作&#xff1a;不同厂家、不同系统之间可以互相兼容&#xff0c;统一标…

经典 算法

算法 算法&#xff08;Algorithm&#xff09;是指解题方案的准确而完整的描述&#xff0c;是一系列解决问题的清晰指令。简单来说&#xff0c;算法 就是解决一个问题的具体方法和步骤。在计算机科学中&#xff0c;算法是程序设计的核心&#xff0c;它决定了程序如何执 行特定的…

【Spark】-- DAG 和宽窄依赖的核心

目录 Spark DAG 和宽窄依赖的核心 一、什么是 DAG? 示例:WordCount 程序的 DAG 二、宽依赖与窄依赖 1. 窄依赖 2. 宽依赖 三、DAG 与宽窄依赖的性能优化 1. 减少 Shuffle 操作 2. 合理划分 Stage 3. 使用缓存机制 四、实际案例分析:同行车判断 五、总结 Spark D…

C#中UI线程的切换与后台线程的使用

文章速览 UI线程切换示例 后台线程使用示例 两者对比适用场景Application.Current.Dispatcher.InvokeTask.Factory.StartNew 执行同步性Application.Current.Dispatcher.InvokeTask.Factory.StartNew 一个赞&#xff0c;专属于你的足迹&#xff01; UI线程切换 在WPF应用程序…

【HTML】个人博客页面

目录 页面视图​编辑 页面代码 解释&#xff1a; HTML (<body>): 使用了更加语义化的HTML5标签&#xff0c;例如<header>, <main>, <article>, <footer>。文章列表使用了<article>包裹&#xff0c;结构清晰。添加了分页导航。使用了Font…

第J1周:ResNet-50算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客 &#x1f356; 原作者&#xff1a;K同学啊 我的环境 语言环境:Python3.8 编译器:Jupyter Lab 深度学习环境:Pytorchtorch1.12.1cu113 torchvision0.13.1cu113 一、准备工作 二、导入数据 三、划分数据…

养生:健康生活的极简攻略

在追求高效生活的当下&#xff0c;养生也能化繁为简。通过饮食、运动、睡眠与心态的精准调节&#xff0c;就能轻松为健康续航。 饮食上&#xff0c;遵循 “均衡、节制” 原则。早餐用一杯热豆浆搭配水煮蛋和半个苹果&#xff0c;唤醒肠胃活力&#xff1b;午餐以糙米饭为主食&am…