35、C语言中晦涩指令与逻辑运算符解析

C语言中晦涩指令与逻辑运算符解析

1. 字符数组运算示例

首先看一个字符数组运算的例子。数组 “item2” 的第一个字符是 ‘e’,其 ASCII 码为 101;数组 “item” 的第一个字符是 ‘W’,其 ASCII 码为 87。用 “item” 减去 “item2”,即 87 - 101 = -14,这个值被存储在变量 “result” 中。当这个值显示在 PORTC 上时,二进制值为 0b11110010。对这个二进制数进行 2 的补码运算,会得到 0b00001110,也就是 14,这表明 0b11110010 代表 -14。

若将指令改为 result == strncmp(item2, item, 1); ,PORTC 上的显示会变为 0b00001110(二进制的 14),这是因为交换了数组顺序,现在的计算是 101 - 87 = 14。

2. C语言中的逻辑运算符

C 语言中有一系列逻辑运算符,常见的及其符号如下:
- AND 函数:有 ‘&’ 和 ‘&&’。
- OR 函数:有 ‘|’ 和 ‘||’。
- EXOR 函数:有 ‘^’。

下面将详细解释这些运算符的作用,并使用 MPLABX 模拟器运行程序,通过单步执行指令和使用观察窗口来查看程序的运行情况。

3. 头文件的使用

为了节省编写程序列表的时间,使用一个之前创建的头文件 PICSetup.h,其内容如下:

void initialise ()
{
    PORTA = 0;
    PORTB = 0;
    PORTC = 0;
    PORTD = 0;
    PORTE = 0;
    TRISA = 0XFF;
    TRISB = 0;
    TRISC = 0;
    TRISD = 0b11111111;
    TRISE = 0;
    ADCON0 = 0;
    ADCON1 = 0b00001111;
    OSCTUNE = 0;
    OSCCON = 0b01110100;
    T0CON = 0b11000111;
}

这实际上是一个名为 initialize 的子例程。要让 PIC 运行头文件中的指令,只需在主程序中调用该子例程。当然,需要在要使用它的列表中包含该头文件,并将其创建为全局头文件。

4. ‘&’ 符号(位 AND 运算符)

‘&’ 是位 AND 运算符,它对各个位进行 AND 运算。两位逻辑 AND 函数的真值表如下:
| B | A | F |
|----|----|----|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |

下面是测试位 AND ‘&’ 运算符的代码:

/*
 * File:   logicsimulationProg.c
 * Author: H H Ward
 *
 * Created on 21 November 2020, 15:56
 */
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
    a = 0;
    b = 0;
    c = 0;
    d = 0;
    a = 2;
    b = 5;
    c = 13;
    while (1)
    {
        d =(a & b);
    }
}

在这个程序中, d = (a & b); 会对变量 ‘a’ 和 ‘b’ 的各个位进行逻辑 AND 运算。只有当 ‘a’ 和 ‘b’ 的对应位都为逻辑 ‘1’ 时,变量 ‘d’ 的对应位才会被设置为逻辑 ‘1’。

例如,当 a = 2 (二进制 0b00000010), b = 5 (二进制 0b00000101)时,只有第 1 位在 ‘a’ 和 ‘b’ 中都是逻辑 ‘1’,所以 d 的值为 0b00000000(十进制 0)。

5. 在 MPLABX 中测试程序

所有这些短程序都可以在 MPLABX 中进行测试。以测试 ‘&’ 运算符为例,操作步骤如下:
1. 创建项目时,在选择工具窗口中选择模拟器作为工具。
2. 构建程序时,从主菜单栏中选择调试选项。
3. 编译程序后,屏幕上会打开一些窗口,可能需要稍微移动它们的位置。
4. 要声明观察窗口,可以从主菜单栏中选择 “windows” 选项,然后选择调试选项卡,再从弹出菜单中选择观察选项卡。
5. 打开窗口后,可以从主菜单栏中选择调试,然后从弹出窗口中选择新建观察,选择要观察的全局符号。
6. 选择确定后,这些观察项将出现在主编辑窗口中。

MPLABX 中模拟过程的按钮及其用途如下:
| 编号 | 用途 |
|----|----|
| 1 | 结束调试会话。 |
| 2 | 暂停:仅在模拟运行时可用。 |
| 3 | 重置:重置模拟并将高亮光标发送到程序的开始处。 |
| 4 | 运行:让 PIC 运行程序。 |
| 5 | 单步跳过:用于让 PIC 跳过指令。在单步执行程序时,如果不想让 PIC 陷入子例程,可以使用此功能。 |
| 6 | 单步进入:用于单步执行程序的指令。 |
| 7 | 单步退出:用于让 PIC 退出一系列指令。 |
| 8 | 运行到光标处:如果程序很长,且知道早期部分运行正常,可以将光标放在想要开始查看的指令处,然后点击键 4 让 PIC 运行程序,PIC 将在插入光标的指令处暂停程序。 |
| 9 | 在光标处设置 PC:将光标放在感兴趣的指令处,然后点击此按钮,PC 的内容将更改为指向该指令。然后点击键 4 让 PIC 从该指令开始运行程序。 |
| 10 | 将光标聚焦在 PC 处:点击此按钮,光标将移动到程序中 PC 当前指向的指令处。 |

下面是一个 mermaid 格式的流程图,展示在 MPLABX 中测试程序的流程:

graph LR
    A[创建项目] --> B[选择模拟器作为工具]
    B --> C[构建程序]
    C --> D[选择调试选项]
    D --> E[编译程序]
    E --> F[打开观察窗口]
    F --> G[选择观察符号]
    G --> H[开始模拟]
6. ‘&’ 运算符的应用

‘&’ 运算符有多种应用,例如:
- 位掩码 :可以确保只将一个变量的选定位数复制到另一个变量中。例如, d = (b & 0b00001111); 会将变量 ‘b’ 的低四位复制到变量 ‘d’ 中。
- 测试特定位 :可以测试变量的特定位是否为逻辑 1。例如,下面的代码用于测试变量 ‘a’ 的第 2 位是否为逻辑 1:

/*
 * File:   logicsimulationProg.c
 * Author: H. H. Ward
 *
 * Created on 21 November 2020, 15:56
 */
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
    a = 0;
    b = 0;
    c = 0;
    d = 0;
    a = 12;
    b = 1;
    c = 0;
    if (a & 4) d = 1;
    else d = 0;
}

在这个例子中, 4 的二进制是 0b00000100,它将第 2 位设置为逻辑 ‘1’。如果变量 ‘a’ 的第 2 位是逻辑 ‘1’,则 d 将被加载为 1;否则, d 将被加载为 0。

7. ‘&&’ 运算符

‘&&’ 运算符的操作与 ‘&’ 不同。它只是测试两个变量是否有任何位被设置为逻辑 ‘1’。如果有,则结果为真;如果任何一个变量为零(即没有位被设置为逻辑 ‘1’),则测试结果为假。

以下是一个使用 ‘&&’ 运算符的示例代码:

/*
 * File:   logicsimulationProg.c
 * Author: H. H. Ward
 *
 * Created on 21 November 2020, 15:56
 */
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
    a = 0;
    b = 0;
    c = 0;
    d = 0;
    a = 5;
    b = 1;
    c = 3;
    while (1)
    {
        if( a &&  b && c ) d= 1;
        else d = 0;
    }
}

在这个例子中,所有三个变量都有一个或多个位被设置为逻辑 ‘1’,所以测试结果为真,变量 ‘d’ 将被加载为 1。如果将变量 ‘c’ 加载为 0,则测试结果为假,‘d’ 将被加载为 0。

8. ‘|’ 运算符(逻辑位 OR 函数)

‘|’ 是逻辑位 OR 函数,它对变量的每个位进行逻辑 OR 运算。两位 OR 的真值表如下:
| B | A | F |
|----|----|----|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |

下面是测试位 OR ‘|’ 运算符的代码:

/*
 * File:   logicsimulationProg.c
 * Author: H. H. Ward
 *
 * Created on 21 November 2020, 15:56
 */
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
    a = 0;
    b = 0;
    c = 0;
    d = 0;
    a = 5;
    b = 9;
    c = 0;
    while (1)
    {
        d = (a | b);
    }
}

在这个程序中, d = (a | b); 会对变量 ‘a’ 和 ‘b’ 的各个位进行逻辑 OR 运算。只要 ‘a’ 或 ‘b’ 的对应位为逻辑 ‘1’,变量 ‘d’ 的对应位就会被设置为逻辑 ‘1’。

例如,当 a = 5 (二进制 0b00000101), b = 9 (二进制 0b00001001)时,第 0 位、第 2 位和第 3 位在 ‘a’ 或 ‘b’ 中是逻辑 ‘1’,所以 d 的值为 0b00001101(十进制 13)。

9. ‘||’ 运算符

‘||’ 是逻辑 OR 运算符,它的工作方式与 ‘|’ 类似,但它将整个八位作为一个字节进行处理。它对三个字节进行逻辑 OR 测试,如果字节 ‘a’ 或字节 ‘b’ 或字节 ‘c’ 或字节 ‘a’、‘b’ 和 ‘c’ 中有任何位被设置为逻辑 ‘1’,则结果为真。

以下是一个使用 ‘||’ 运算符的示例代码:

/*
 * File:   logicsimulationProg.c
 * Author: H. H. Ward
 *
 * Created on 21 November 2020, 15:56
 */
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
    a = 0;
    b = 0;
    c = 0;
    d = 0;
    a = 5;
    b = 9;
    c = 13;
    while (1)
    {
        if( a || b || c ) d= 1;
        else d = 0;
    }
}

在这个例子中,所有三个变量都有一些位被设置为逻辑 ‘1’,所以结果为真,‘d’ 将被加载为 1。只有当所有变量都被设置为 0 时,测试结果才为假,‘d’ 将被加载为 0。

我们还可以使用这个逻辑函数来测试变量的任何位是否被设置为逻辑 ‘1’。例如:

/*
 * File:   logicsimulationProg.c
 * Author: H. H. Ward
 *
 * Created on 21 November 2020, 15:56
 */
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
    a = 0;
    b = 0;
    c = 0;
    d = 0;
    a = 5;
    b = 0;
    c = 13;
    while (1)
    {
        if( a || 0 ) d= 1;
        else d = 0;
    }
}

if ( a || 0 ) d= 1; 只是测试变量 ‘a’ 的任何位是否被设置为逻辑 ‘1’。如果是,则结果为真,‘d’ 将被加载为 1;否则,‘d’ 将被加载为 0。

通过以上内容,我们详细介绍了 C 语言中一些晦涩指令和逻辑运算符的使用方法和应用场景,希望能帮助你更好地理解和运用这些知识。

10. 逻辑运算符总结

为了更清晰地对比这些逻辑运算符,我们将它们的特点总结如下:
| 运算符 | 类型 | 作用 | 示例 |
| ---- | ---- | ---- | ---- |
| & | 位运算符 | 对各个位进行逻辑 AND 运算,只有对应位都为 1 时结果位才为 1 | d = (a & b); |
| && | 逻辑运算符 | 测试两个变量是否有任何位被设置为 1,都有则结果为真 | if (a && b) d = 1; |
| | | 位运算符 | 对各个位进行逻辑 OR 运算,只要对应位有一个为 1 结果位就为 1 | d = (a \| b); |
| || | 逻辑运算符 | 将整个字节作为一个整体进行逻辑 OR 测试,只要有一个字节有位为 1 结果就为真 | if (a \|\| b) d = 1; |

下面是一个 mermaid 格式的流程图,展示不同逻辑运算符的判断流程:

graph TD
    A[开始] --> B{选择运算符}
    B --> C{& 运算符}
    B --> D{&& 运算符}
    B --> E{\| 运算符}
    B --> F{\|\| 运算符}
    C --> G{对应位都为 1?}
    G --> H[结果位为 1]
    G --> I[结果位为 0]
    D --> J{变量都有位为 1?}
    J --> K[结果为真]
    J --> L[结果为假]
    E --> M{对应位有一个为 1?}
    M --> N[结果位为 1]
    M --> O[结果位为 0]
    F --> P{字节有位为 1?}
    P --> Q[结果为真]
    P --> R[结果为假]
11. 实际应用案例分析

在实际的编程中,这些逻辑运算符有着广泛的应用。以下通过几个具体的案例来进一步说明。

案例一:状态检测
假设我们有一个系统,需要检测多个设备的状态。每个设备的状态用一个字节的某一位来表示,例如设备 1 的状态用第 0 位表示,设备 2 的状态用第 1 位表示,以此类推。我们可以使用逻辑运算符来判断所有设备是否都正常工作。

#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>

// 定义设备状态变量
unsigned char device_status;

void main()
{
    // 初始化设备状态
    device_status = 0b00000000;

    // 模拟设备 1 和设备 2 正常工作
    device_status |= 0b00000011;

    // 检查所有设备是否都正常工作
    if ((device_status & 0b00000011) == 0b00000011)
    {
        // 所有设备正常工作
        // 可以在这里添加相应的处理代码
    }
    else
    {
        // 有设备出现故障
        // 可以在这里添加相应的处理代码
    }

    while (1)
    {
        // 主循环
    }
}

在这个案例中,我们使用了 | 运算符来设置设备的状态,使用 & 运算符来检查设备的状态。

案例二:条件判断优化
在一些复杂的条件判断中,合理使用逻辑运算符可以使代码更加简洁和高效。例如,我们需要判断一个变量是否在某个范围内。

#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>

// 定义变量
unsigned char value;

void main()
{
    // 初始化变量
    value = 10;

    // 判断变量是否在 5 到 15 之间
    if ((value >= 5) && (value <= 15))
    {
        // 变量在范围内
        // 可以在这里添加相应的处理代码
    }
    else
    {
        // 变量不在范围内
        // 可以在这里添加相应的处理代码
    }

    while (1)
    {
        // 主循环
    }
}

在这个案例中,我们使用了 && 运算符来组合两个条件,使判断更加清晰。

12. 注意事项

在使用这些逻辑运算符时,还需要注意以下几点:
1. 运算符优先级 :不同的逻辑运算符有不同的优先级,例如 && 的优先级高于 || 。在编写代码时,要注意使用括号来明确运算顺序,避免出现意外的结果。
2. 短路求值 && || 运算符具有短路求值的特性。对于 && 运算符,如果第一个操作数为假,则不会计算第二个操作数;对于 || 运算符,如果第一个操作数为真,则不会计算第二个操作数。在编写代码时,要考虑这个特性对程序的影响。
3. 位运算与逻辑运算的区别 :位运算符是对二进制位进行操作,而逻辑运算符是对整个表达式的真假进行判断。在使用时要根据具体需求选择合适的运算符。

13. 总结

通过对 C 语言中这些逻辑运算符的详细介绍和实际应用案例分析,我们可以看到它们在编程中有着重要的作用。合理使用这些运算符可以使代码更加简洁、高效,并且能够实现一些复杂的功能。

在实际编程中,我们要根据具体的需求选择合适的运算符,同时要注意运算符的优先级和短路求值等特性。通过不断地练习和实践,我们可以更加熟练地运用这些逻辑运算符,提高编程水平。

希望本文能够帮助你更好地理解和掌握 C 语言中的逻辑运算符,让你在编程的道路上更加得心应手。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值