C语言联合体(Union)实战:如何用1个变量存储3种不同类型数据?

超详细C语言联合体union详解 文章目录前言一、联合(共用体)定义二、联合的特点及运用三、联合的大小计算总结 前言 上一期C语言快速入门我们学习了枚举类型及相关知识点,这期我们来跟着笔者学习一下联合体相关知识,相信聪明的你一定会有所收获! 提示:以下是本篇文章正文内容,下面案例可供参考 一、联合(共用体)定义 联合是一种特殊的自定义类型,该种类型定义的变量也包含一系列的成员,特征是这些成员共用同一块空间,所以联合体也被称为共用体。 代码如下(示例): #include<stdio.h> union Un//联合类型的声明. 阅读详情

C语言联合体与位域:内存布局的艺术与实战精要

在嵌入式开发和底层系统编程的世界里,每一字节的内存都弥足珍贵。当你的程序需要在资源受限的微控制器上运行,或者需要处理来自传感器、网络协议包的原始字节流时,传统的变量定义方式往往显得笨拙且低效。你是否曾为解析一个包含多种可能数据类型的通信帧而定义多个变量,却只用到其中一个而感到浪费?是否曾为访问硬件寄存器中某个特定控制位而不得不进行繁琐的位掩码操作?

这正是C语言中**联合体(Union)和位域(Bit-field)**这两项古老而强大的特性大放异彩的领域。它们不是语法糖,而是赋予程序员直接、精细控制内存布局的“手术刀”。掌握它们,意味着你能写出更紧凑、更高效、更贴近硬件的代码。本文将带你深入这两个特性的核心,避开教科书式的罗列,聚焦于实际项目中你会遇到的真实场景、陷阱和最佳实践。

1. 联合体:内存空间的“变形金刚”

联合体的核心思想是内存共享。它定义了一块内存区域,允许你以多种不同的“视角”去解释和使用它。这听起来有些抽象,我们从一个嵌入式开发中常见的例子开始。

1.1 传感器数据包的优雅解析

假设你正在开发一个环境监测节点,它通过I2C总线读取一个温湿度传感器。传感器返回一个4字节的数据包,但其格式根据模式不同而变:

  • 模式A:前2字节是温度(int16_t),后2字节是湿度(uint16_t)。
  • 模式B:4字节全部表示一个高精度的温度值(float)。
  • 模式C:第1字节是状态(uint8_t),后3字节是原始ADC读数(一个24位整数,用3个uint8_t表示)。

用传统方法,你可能需要定义多个变量,并用if-else分支来分别处理。而使用联合体,你可以这样设计:

typedef union {
    uint8_t raw[4]; // 原始字节数组,用于接收I2C数据

    struct {
        int16_t temperature; // 模式A:温度
        uint16_t humidity;    // 模式A:湿度
    } mode_a;

    float temperature_high_precision; // 模式B:高精度温度

    struct {
        uint8_t status;               // 模式C:状态字节
        uint8_t adc_raw[3];           // 模式C:ADC原始数据
    } mode_c;
} sensor_packet_t;

sensor_packet_t packet;

// 假设从I2C读取了4个字节到 packet.raw
i2c_read(sensor_addr, packet.raw, 4);

// 根据已知的模式进行解析
if (current_mode == MODE_A) {
    printf("Temp: %d, Humidity: %u\n", packet.mode_a.temperature, packet.mode_a.humidity);
} else if (current_mode == MODE_B) {
    printf("Temp: %.2f\n", packet.temperature_high_precision);
} else if (current_mode == MODE_C) {
    printf("Status: 0x%02X, ADC: %02X%02X%02X\n",
           packet.mode_c.status,
           packet.mode_c.adc_raw[0],
           packet.mode_c.adc_raw[1],
           packet.mode_c.adc_raw[2]);
}

注意:联合体本身不存储“当前是哪个成员有效”的信息。这是使用联合体时最关键的一点。你必须通过其他途径(如一个独立的枚举变量、数据包中的类型字段或上下文)来跟踪当前应如何解释联合体中的数据。忘记这一点是导致bug的常见原因。

这种设计的优势显而易见:

  • 内存零浪费:无论数据是哪种格式,都只占用4字节。
  • 访问直观:无需手动进行指针类型转换或字节拼接,代码可读性高。
  • 与硬件对齐:raw[4]成员使得从总线读取原始字节变得异常简单。

1.2 深入内存:字节序与类型转换

联合体是观察和理解系统**字节序(Endianness)**的绝佳工具。字节序决定了多字节数据在内存中的存储顺序。

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

union byte_order_demo {
    uint32_t value;
    uint8_t bytes[4];
};

int main() {
    union byte_order_demo converter;
    converter.value = 0x12345678;

    printf("整数值: 0x%08X\n", converter.value);
    printf("字节[0]: 0x%02X\n", converter.bytes[0]);
    printf("字节[1]: 0x%02X\n", converter.bytes[1]);
    printf("字节[2]: 0x%02X\n", converter.bytes[2]);
    printf("字节[3]: 0x%02X\n", converter.bytes[3]);

    return 0;
}

在常见的x86或ARM Cortex-M系列(小端序)机器上,输出会是:

整数值: 0x12345678
字节[0]: 0x78  // 最低有效字节 (LSB) 在低地址
字节[1]: 0x56
字节[2]: 0x34
字节[3]: 0x12  // 最高有效字节 (MSB) 在高地址

如果在大端序的机器(如某些PowerPC或网络字节序)上运行,输出则会相反。理解这一点对网络编程(需要处理htonl/ntohl转换)和与特定硬件交互至关重要。

联合体也能安全地实现一些特定类型间的位模式转换,例如快速检查一个float的符号位,或者实现一个简单的浮点数比较(虽然不推荐用于精确比较)。

union float_int {
    float f;
    uint32_t u;
};

int float_get_sign(float x) {
    union float_int fi;
    fi.f = x;
    // 提取IEEE 754单精度浮点数的符号位(最高位)
    return (fi.u >> 31) & 0x1;
}

1.3 联合体的典型应用场景与陷阱

除了数据包解析,联合体在以下场景中也非常有用:

  • 实现变体类型(Variant):结合一个标签(tag)枚举,可以创建一个能存储多种类型但一次只使用一种的数据结构。这在实现简单的解释器或配置系统时很有用。
  • 节省内存的结构体成员:当结构体的某些成员互斥时,可以将它们放入联合体。
  • 访问硬件寄存器:同一物理寄存器在不同模式下可能有不同功能,可以用联合体来定义不同的视图。

然而,使用联合体时必须警惕以下陷阱:

  1. 未初始化的访问:访问最近未被写入的成员是未定义行为(UB)。编译器可能不会报错,但结果不可预测。
  2. 类型双关(Type Punning)的严格别名规则:在C语言中,通过一种类型的指针去访问另一种类型的对象(严格别名规则)通常是未定义行为。虽然通过联合体进行类型双关是许多编译器的扩展支持(并被C99标准的一个脚注所暗示),但为了最大可移植性,最好使用memcpy或编译器提供的类型双关内置函数。
  3. 对齐问题:联合体的大小会按其最大成员的对齐要求进行对齐。这可能导致内存浪费。例如,一个包含char和double的联合体,其大小可能是8字节(double的对齐要求),而不是1+8=9字节。

2. 位域:比特级的精细控制

如果说联合体让你能以不同方式看待同一块内存,那么位域则允许你在这块内存上划分出更精细的“产权”。它让你能在结构体内部,以**比特(bit)**为单位来定义成员。

2.1 基础语法与内存布局

位域的基本语法是在结构体成员声明后加上冒号和位数:

struct protocol_header {
    unsigned int version : 4;  // 使用4个比特表示版本号
    unsigned int type    : 2;  // 使用2个比特表示报文类型
    unsigned int flags   : 3;  // 使用3个比特表示标志位
    unsigned int length  : 10; // 使用10个比特表示载荷长度
    // 编译器可能会在此处插入填充位,以满足unsigned int的对齐
};

这个结构体理论上只需要 4+2+3+10 = 19 个比特,不到3个字节。但sizeof(struct protocol_header)很可能返回4或8,这取决于unsigned int的大小(通常是4字节)和编译器的对齐规则。

位域布局的编译器依赖性是位域最大的“坑”。C标准没有规定位域在存储单元内的具体布局顺序(是从左到右还是从右到左?是否允许跨存储单元?)。不同编译器、甚至同一编译器的不同平台,行为都可能不同。

特性说明可移植性影响
分配单元(底层类型)通常是int, unsigned int, _Bool。C99后也可以是其他整数类型。使用unsigned int最通用。
位域内的位顺序高位在先(大端)还是低位在先(小端)?高度依赖实现。与平台字节序有关,但非绝对。
跨单元行为当一个位域成员在一个存储单元中放不下时,是跨单元存放还是从新单元开始?高度依赖实现。
未命名位域用于占位填充,如 unsigned int : 4;。可移植性好,用于显式控制布局。
零宽度位域unsigned int : 0; 强制下一个位域从新的存储单元开始。可移植性好,是强制对齐的有效手段。

由于这些不确定性,位域不适合用于需要跨平台或跨编译器交换数据的场景(如网络协议、文件格式)。在这些场景中,应使用显式的位掩码和移位操作。

2.2 嵌入式开发中的王牌应用:硬件寄存器映射

尽管有可移植性问题,但在针对特定硬件和编译器的嵌入式开发中,位域是访问硬件寄存器的神器。微控制器的外设寄存器通常被组织成一个个位字段,每个字段控制特定的功能。

假设我们有一个控制GPIO引脚的32位寄存器,其布局如下:

  • Bit 0: ENABLE (使能)
  • Bits 2-1: MODE (模式: 00=输入, 01=输出, 10=复用, 11=模拟)
  • Bits 5-3: SPEED (速度)
  • Bits 7-6: PULL (上拉/下拉)
  • Bits 31-8: 保留

用位域可以非常直观地定义这个寄存器:

typedef struct {
    volatile uint32_t ENABLE : 1;
    volatile uint32_t        : 1; // 保留位1
    volatile uint32_t MODE   : 2;
    volatile uint32_t SPEED  : 3;
    volatile uint32_t PULL   : 2;
    volatile uint32_t        : 24; // 保留剩余位
} gpio_register_t;

#define GPIOA_CTRL ((gpio_register_t *)0x40020000)

void gpio_init_as_output(void) {
    GPIOA_CTRL->ENABLE = 1;
    GPIOA_CTRL->MODE = 0b01; // 输出模式
    GPIOA_CTRL->SPEED = 0b010; // 中速
    GPIOA_CTRL->PULL = 0b00; // 无上拉下拉
}

代码中的volatile关键字至关重要,它告诉编译器这个变量可能被硬件异步修改,禁止对其进行优化(如缓存读取、重排指令)。

提示:在访问内存映射的硬件寄存器时,必须使用volatile限定符,否则可能导致编译器生成错误的代码,使得对寄存器的读写操作被优化掉或顺序错乱。

2.3 位域使用的限制与技巧

位域成员有一些特殊的限制:

  • 不能取地址:因为地址是以字节为单位的,无法指向一个比特。&(reg.ENABLE)是非法操作。
  • 不能是静态成员。
  • 不能构成数组。

一个常见的技巧是使用匿名结构体简化访问:

typedef struct {
    union {
        volatile uint32_t CR;
        struct {
            volatile uint32_t ENABLE : 1;
            volatile uint32_t MODE   : 2;
            // ... 其他位域
        };
    };
} gpio_t;
// 现在可以直接用 gpio.CR 访问整个寄存器,也可以用 gpio.ENABLE 访问特定位

3. 联合体与位域的强强联合

将联合体和位域结合使用,可以创造出既节省内存又便于访问的复合数据结构。这是嵌入式固件和驱动开发中的经典模式。

3.1 状态寄存器的标准范式

回顾一下GPIO寄存器的例子。我们通常需要两种操作方式:

  1. 一次性读取或写入整个寄存器的值(例如在初始化时从默认值加载)。
  2. 单独修改或查询某个特定的控制位(例如在中断服务程序中快速切换一个标志)。

联合体加位域的组合完美满足了这一需求:

typedef union {
    volatile uint32_t full; // 完整的32位寄存器值
    struct {
        volatile uint32_t ENABLE : 1;
        volatile uint32_t        : 1;
        volatile uint32_t MODE   : 2;
        volatile uint32_t SPEED  : 3;
        volatile uint32_t PULL   : 2;
        volatile uint32_t        : 23;
    } bits;
} gpio_ctrl_reg_t;

gpio_ctrl_reg_t * const GPIOA = (gpio_ctrl_reg_t *)0x40020000;

// 用法示例:
void gpio_configure(void) {
    // 方式1:整体操作,写入一个已知的初始值
    GPIOA->full = 0x00000080;

    // 方式2:位操作,只修改速度位,不影响其他位
    GPIOA->bits.SPEED = 0b101; // 切换到高速模式

    // 方式3:读取特定状态位
    if (GPIOA->bits.ENABLE) {
        // GPIO已使能
    }

    // 方式4:读取整个寄存器进行校验或保存
    uint32_t backup = GPIOA->full;
}

这种模式如此常见,以至于许多硬件厂商提供的芯片头文件(如STM32的stm32fxxx.h)中,大量使用了这种“联合体+位域+结构体”的定义方式来描述所有外设寄存器。

3.2 协议字段的高效封装

在通信协议中,一个字节的头常常包含多个标志位和短字段。例如,一个经典的TCP报文头片段:

typedef union {
    uint8_t raw;
    struct {
        uint8_t cwr : 1; // Congestion Window Reduced
        uint8_t ece : 1; // ECN-Echo
        uint8_t urg : 1; // Urgent pointer valid
        uint8_t ack : 1; // Acknowledgment valid
        uint8_t psh : 1; // Push function
        uint8_t rst : 1; // Reset connection
        uint8_t syn : 1; // Synchronize sequence numbers
        uint8_t fin : 1; // No more data from sender
    } flags;
} tcp_flags_t;

void process_tcp_packet(uint8_t flags_byte) {
    tcp_flags_t f;
    f.raw = flags_byte;

    if (f.flags.syn && f.flags.ack) {
        // 处理SYN-ACK包
        handle_syn_ack();
    } else if (f.flags.fin) {
        // 处理连接关闭
        handle_fin();
    }
    // ... 其他标志处理
}

这种方式比手动使用位掩码(如if (flags_byte & 0x02))要清晰、安全得多,可读性极佳。

4. 实战进阶:可移植性、调试与替代方案

了解了基本用法和强大之处后,我们必须面对其最大的挑战:可移植性和调试复杂性。

4.1 确保可移植性的策略

如果你的代码需要跨平台或使用不同编译器,请慎用位域。如果必须使用,请遵循以下策略:

  1. 使用静态断言(Static Assert):在C11或C++11及以上版本中,使用_Static_assert或static_assert来确保结构体大小符合预期。

    #include <assert.h>
    // 确保我们的位域结构正好是期望的大小
    static_assert(sizeof(struct protocol_header) == 4,
                  "protocol_header size mismatch, check compiler packing!");
    
  2. 明确编译器打包指令:大多数编译器提供#pragma pack或__attribute__((packed))来控制结构体对齐。但请注意,过度打包可能影响性能(某些架构上未对齐访问会导致硬件异常或性能下降)。

    // GCC/Clang
    struct __attribute__((packed)) my_packed_struct {
        // ... 位域定义
    };
    
    // MSVC
    #pragma pack(push, 1)
    struct my_packed_struct {
        // ... 位域定义
    };
    #pragma pack(pop)
    
  3. 编写平台适配层:为位域访问封装统一的接口,在接口内部根据平台定义使用位域或位操作。

    // port.h
    #ifdef PLATFORM_A
    #define GET_FLAG(reg) ((reg).bits.flag)
    #define SET_FLAG(reg, val) do { (reg).bits.flag = (val); } while(0)
    #else
    // 平台B使用位掩码
    #define FLAG_MASK (1u << 2)
    #define GET_FLAG(reg) (((reg).full) & FLAG_MASK)
    #define SET_FLAG(reg, val) \
        do { \
            if (val) (reg).full |= FLAG_MASK; \
            else (reg).full &= ~FLAG_MASK; \
        } while(0)
    #endif
    

4.2 调试位域与联合体

在调试器中查看联合体和位域变量有时会令人困惑。以GDB为例:

(gdb) p/x my_union
$1 = {full = 0x12345678, bits = {ENABLE = 0x0, MODE = 0x3, ...}}
(gdb) p/t my_union.full
$2 = 10010001101000101011001111000  # 二进制显示
(gdb) x/4xb &my_union                # 查看内存原始字节
0x7fffffffde34: 0x78    0x56    0x34    0x12

理解你的调试器如何显示这些类型,并学会查看原始内存,是排查相关问题的关键。

4.3 替代方案:显式的位操作

当可移植性是最高优先级时,放弃位域,使用传统的位掩码和移位操作是更安全的选择。虽然代码稍显冗长,但行为是明确且标准的。

// 使用位域(不可移植但简洁)
union {
    uint32_t reg;
    struct { uint32_t en:1, mode:2, speed:3; } bits;
} u;
u.bits.mode = 2;

// 使用位操作(可移植但繁琐)
#define MODE_POS (1)
#define MODE_MASK (0x3u << MODE_POS)
uint32_t reg;
reg = (reg & ~MODE_MASK) | ((2u << MODE_POS) & MODE_MASK);

// 或者封装成宏/内联函数
static inline void set_mode(uint32_t *reg, uint32_t mode) {
    *reg = (*reg & ~MODE_MASK) | ((mode << MODE_POS) & MODE_MASK);
}
set_mode(&reg, 2);

C++提供了std::bitset,而C语言在C23标准中引入了_BitInt(N)类型,它们都是更现代、更安全的位操作替代品,值得在新项目中考虑。

联合体和位域是C语言赋予开发者的底层超能力。它们让你能像硬件工程师一样思考内存,写出极致高效的代码。然而,这份力量伴随着责任。你必须清楚地知道编译器在背后做了什么,你的代码所运行的平台有何特性。在嵌入式、驱动、协议栈等贴近硬件的领域,熟练运用它们是高级工程师的标志。但在追求高可移植性的应用层代码中,或许更保守的位操作才是明智之选。理解两者的优劣,在合适的场景选择合适的技术,这才是真正的专家之道。

【C语言】联合体-共用体 (union) 详解 C语言,联合体,共用体,union 阅读详情

相关推荐

C语言联合体/共用体/union,枚举使用大全

文章目录一、前言二、联合体1.联合体基础2. 联合体的使用方法和使用场景2.1 多种访问内存途径共存2.2 联合体union和大小端(big-endian、little-endian)2.3 联合体union所占内存空间大小2.4 联合体union适用场合2.5 联合体使用的几个小技巧2.5 本质&进阶三、枚举1.枚举基础知识2.枚举变量的定义3.枚举的使用场景和使用方法3.1 枚举的遍历3.2 将整数转换为枚举 一、前言 构造类型或复杂类型主要有结构体、联合体和枚举。 结构体我们一般使用的比较频繁

qq_41854911的博客 3764

C语言-联合体union

C语言-联合体union

让你爱上电路设计 3万+

C语言数据类型之联合体Union

1、联合体Union和结构体Struct的比较: 联合体Union和结构体Struct均属于特殊的数据类型,都允许成员是不同类型的值。两者的区别在于结构体的各个成员会占用不同的内存,互相之间没有影响;而联合体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),联合体占用的内存等于最长的成员占用的内存。 2、联合体Union语法: union tag //tag 即联合体名称 { int member1;//联合体成员,成员之间

jianshuilan_0613的博客 1530

C/C++中的联合体union介绍

目录 union定义与简单使用 内存分配与所占空间 多种访问内存途径共存 数据存储位置 union应用之寄存器读取 union,中文名“联合体、共用体”,在某种程度上是类似结构体struct的一种数据结构,联合体(union)和结构体(struct)同样可以包含很多种数据类型和变量。

会意的博客 4万+

CamoFox MCP:让AI助手隐身操作浏览器的反检测自动化实战

浏览器自动化是提升工作效率和实现数据采集的关键技术,其核心原理在于通过程序脚本模拟人类在网页上的交互行为。传统方案如Selenium或Playwright虽功能强大,但需要开发者编写复杂脚本并处理反爬机制。随着AI Agent技术的发展,自然语言驱动的自动化成为新趋势,它能将任务规划与逻辑判断交由AI处理,大幅降低使用门槛。Model Context Protocol(MCP)作为连接AI与外部工具的标准协议,在此场景下价值凸显,它使得AI助手能直接调用丰富的浏览器操作工具。CamoFox MCP创新性地将

weixin_42551967的博客 727

AMCL代码详解(六)amcl中的重采样

每次都从w1左边的竖线开始转,显而易见,转到w1的概率为0-w1之间的随机数,转到w2的概率为w1到w1+w2之间的随机数,转到w3的概率为w1+w2到w1+w2+w3之间的随机数,后面的依次类推。当某个粒子的权值较大的时候,产生的随机数落在相应区间的概率就会增大,从而实现了对权值大粒子的多次复制,权值小的粒子的剔除。可以看出,在整个重采样的过程中,粒子进行了两次种情况的刷新,一种是随机生成的新的粒子,一种是对原来的粒子的复制。得到的值越大,说明粒子的权重越小,当前粒子的可信度比较小,需要重采样粒子。

YiYeZhiNian的博客 1579

C语言自定义类型变量——联合体(union)

/一.同时创建模板和变量char c;int i;}un;//二.先定义模板,再定义变量char c;int i;//三.匿名联合体(一次性的,后面不能再次使用它定义新变量)unionchar c;int i;}un1, un2;//使用typedefchar c;int i;}U_data;

2301_80827065的博客 4635

告别倍福开发板:手把手教你用SSC工具为STM32生成EtherCAT从站代码

本文详细介绍了如何使用SSC工具为STM32生成EtherCAT从站代码,帮助开发者在不依赖倍福开发板的情况下实现高效的工业以太网通信。通过SSC工具的配置、XML文件设计、代码移植与硬件适配等步骤,开发者可以轻松构建自定义的EtherCAT通信系统,提升工业自动化项目的灵活性和效率。

weixin_33925615的博客 410

C语言联合体union详解

该种类型定义的变量也包含一系列的成员,特征是这些成员共用同一块空间,所以联合体也被称为共用体。

m0_53263647的博客 1万+

ESP32语音交互实战:离线唤醒与DeepSeek大模型集成

本文详细介绍了如何将ESP32-S3开发板与天问ASRPRO语音模块结合,实现离线语音唤醒并集成DeepSeek大模型的智能交互系统。通过串口通信与API调用,系统可处理本地指令及复杂语义请求,适用于低成本、高隐私保护的AIoT语音交互场景。

rust6ferris的博客 869

生物信息学工具链搭建:用conda一键搞定MCScanX所有依赖(Ubuntu20.04实测)

本文详细介绍了在Ubuntu20.04系统上使用conda一键部署MCScanX及其所有依赖的高效方法,解决了传统源码编译安装中的依赖冲突问题。通过conda环境管理工具,研究者可以快速搭建生物信息学工具链,实现基因组共线性分析的高效运行,显著提升研究效率。

backprop5master的博客 247

C语言 | 联合体(union)、typedef

一、联合体union 1.联合体含义 联合 union 是一个能在同一个存储空间存储不同类型数据的类型; 联合体所占的内存长度等于其最长成员的长度倍数,也有叫做共用体; 同一内存段可以用来存放几种不同类型的成员,但每一瞬时只有一种起作用;共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被覆盖; 共用体变量的地址和它的各成员的地址都是同一地址。 2.联合体与结构体 结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会

该用户还没想到好的昵称的博客 3832

不止是打字机效果:手把手教你用SpannableStringBuilder打造Android富文本AI对话界面

本文详细介绍了如何使用SpannableStringBuilder在Android平台上构建专业级AI对话界面,涵盖流式文本处理、富文本解析、交互优化等核心技术。通过实战代码示例,帮助开发者实现类似DeepSeek的AI产品交互效果,提升用户体验和应用专业度。

weixin_28358083的博客 198

联合体:C语言中的数据类型魔法

本文旨在深入探讨C语言中的联合体(Union)机制,为C语言开发者提供关于联合体的全面理解。文章首先概述了联合体的定义和特性,随后详细分析了联合体的实现、操作和实际应用。最后,通过技术总结,强调了联合体在编程中的重要性。联合体(Union)是C语言中一种特殊的数据类型,它允许在同一个内存位置存储不同类型的数据。单一内存位置:联合体中的所有成员共享同一个内存位置,这意味着它们共用同一块内存空间。动态大小:联合体的成员可以有不同的数据类型和大小,但它们共享的空间大小取决于成员中最大的那个。成员访问。

极客代码 1586

华为Ascend C算子开发能力认证(中级)(个人记录,有完整代码,已通过认证,仅供参考)

本文介绍了在昇腾NPU环境下实现Sigmoid算子的完整流程。首先需要在华为云ModelArts-Notebook或开发者套件上搭建环境,要求CANN版本为8.0.0.beta1。主要内容包括:1)实现SigmoidCustom算子的kernel侧核函数代码;2)完成host侧Tiling结构体实现;3)支持Float16数据类型。代码实现部分详细展示了核函数计算流程、数据拷贝和牛顿迭代优化方法。最后介绍了编译部署流程,包括环境配置、代码上传、编译执行等步骤,并提供了提交规范说明。该实现通过调用Ascend

qq_73044452的博客 1107

基于STM32F103的智能门禁门锁门卫系统设计

本文设计了一种基于STM32F103单片机的智能门禁系统,集成了密码、射频IC卡和指纹识别三种验证方式。系统采用模块化设计,包含MFRC522射频模块、AS608指纹模块、矩阵键盘、OLED显示和舵机控制等硬件,实现了身份验证、密码修改、IC卡/指纹管理以及安全防护功能。测试结果表明系统响应迅速(密码验证250ms、指纹验证600ms)、功耗低(待机50mA),且具备掉电密码保存功能。该系统操作简便、功能完善,适用于家庭和办公场所,具有较高实用价值。未来可扩展远程控制、人脸识别等功能以进一步提升智能化水平。

3254968421的博客 319

C# 实现C的Union联合体

C# 实现C++ Union联合体前言联合体概念联合体union的基本特性——和struct的同与不同双刃剑——多种访问内存途径共存代码 前言 在使用STM32给上层Unity发串口消息的时候,下位机使用了C++的Union联合体作为数据类型,而Unity使用的C#并没有Union联合体这一概念,所以记录下来。 联合体概念 联合体union的基本特性——和struct的同与不同 union,中文名“联合体、共用体”,在某种程度上类似结构体struct的一种数据结构,共用体(union)和结构体(struct

SlowFeather's blog 6998

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

联合体union详解

联合体union的基本用法,内存计算,对齐,大小端判断应用,与结构体的区别

m0_67669662的博客 1854

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

C语言联合体(union)

一、C语言联合体(union) 1. 概念:联合体里面所有成员都共用一块内存,使用时候,所有成员属性选一个。 2. 定义 -定义联合体数据类型 union sorce { int a; char b; short c; } 定义联合体变量 union a aaa; -访问联合体的成员 aaa.a = 5 联合体内存分分配原理如图所示 所以成员变量中char类型数据只占其中的一个字节,short类型数据只占其中的两个字节。 二、利用联合体可以判断主机的大小端序 大端序:数据

weixin_37552254的博客 2826

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain&#39;s apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath(&#39;DeepLearnToolbox&#39;));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand(&#39;state&#39;,0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W&#39;); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand(&#39;state&#39;,0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = &#39;sigm&#39;;%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, &#39;Too big error&#39;);```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand(&#39;state&#39;,0)sae = saesetup([784 100]);sae.ae{1}.activation_function = &#39;sigm&#39;;sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)&#39;)% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = &#39;sigm&#39;;nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, &#39;Too big error&#39;);```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x&#39;,28,28,60000))/255;test_x = double(reshape(test_x&#39;,28,28,10000))/255;train_y = double(train_y&#39;);test_y = double(test_y&#39;);%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you&#39;ll get around 1.2% errorrand(&#39;state&#39;,0)cnn.layers = { struct(&#39;type&#39;, &#39;i&#39;) %input layer struct(&#39;type&#39;, &#39;c&#39;, &#39;outputmaps&#39;, 6, &#39;kernelsize&#39;, 5) %convolution layer struct(&#39;type&#39;, &#39;s&#39;, &#39;scale&#39;, 2) %sub sampling layer struct(&#39;type&#39;, &#39;c&#39;, &#39;outputmaps&#39;, 12, &#39;kernelsize&#39;, 5) %convolution layer struct(&#39;type&#39;, &#39;s&#39;, &#39;scale&#39;, 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, &#39;Too big error&#39;);```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, &#39;Too big error&#39;);%% ex2 neural net with L2 weight decayrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex3 neural net with dropoutrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex4 neural net with sigmoid activation functionrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.activation_function = &#39;sigm&#39;; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex5 plotting functionalityrand(&#39;state&#39;,0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = &#39;softmax&#39;; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand(&#39;state&#39;,0)nn = nnsetup([784 20 10]); nn.output = &#39;softmax&#39;; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

C语言联合体union的用法(非常详细,附带示例)

联合体的定义语法与结构体类似,但使用 union 关键字代替 struct,以下是联合体的定义语法:union 联合体名称 {数据类型1 成员1;数据类型2 成员2;...数据类型n 成员n;在这个语法中,union是关键字,用于声明一个联合体。联合体名称是我们自定义的类型名称,符合C语言标识符命名规则。大括号内列出了联合体的所有成员,每个成员都有自己的数据类型和名称。注意,定义联合体是一个完整的语法,最后的分号;不能省略。

leiming6的博客 827

C/C++语言中union联合体存在的意义以及应用实例

C语言中union联合体存在的意义 共用体是什么? 如上图所示,共用体正如“共有”关键字所描述的一样,共用体所占的数据空间是共用体中最大的数据类型成员所占用的空间,这些成员并不是随意放置,而是用有相同的首地址。因此,我们在任意时刻只可以按照一个数据类型对共用体进行赋值,共用体中这些成员的关系是“或”,即“不是你死就是我活”。 其实我们可以这样说“共用体其实可以在任意时刻被当作其任意一个数据成员来赋值使用”。共用体的出现基本上实现了我们追求的“万能数据类型”。 共用体与结构体的区别 ..

超级霸霸强的博客 3403

【C语言】【union联合体】

Union,即联合体,将几种数据类型联合起来的一种数据结构,且共用同一个内存空间。 例如,用24bit表示一个像素点,包含 RED、GREEN、BLUE,每种颜色8bit。使用联合体便可以定义如下: typedef union { struct __attribute__ ((packed)) { uint8_t r, g, b; }; uint32_t rgb; }...

iStoneWalker的博客 908

C语言联合体union详解与实例

和结构体类似,联合体(union)是C语言中一种自定义数据类型。联合体中可以定义多个类型的成员变量,但所有成员共享同一块内存区域,所以联合体在当前时刻只存储一个成员变量值。

SEU123WW的博客 1534

C语言联合体(union)实战:如何用1个变量存3种数据?附内存布局图解

本文深入解析C语言联合体(union)的工作原理及实战应用,通过内存布局图解和嵌入式开发案例,展示如何高效利用联合体实现1个变量存储3种数据类型。特别适合嵌入式系统开发中需要节省内存资源的场景,涵盖硬件寄存器操作、协议解析等实用技巧。

7up55的博客 618

C语言中的union联合变量是什么意思

什么是联合变量 c语言中的union 是联合体,就是一个多个变量的结构同时使用一块内存区域,区域的取值大小为该结构中长度最大的变量的值 联合的定义 定义一个联合类型的一般形式为: union 联合名 { 成员表 }; 成员表中含有若干成员,成员的一般形式为: 类型说明符 成员名 。成员名的命名应符合标识符的规定。例如: union perdata { int class; ...

czdyhh的博客 3777
上一篇: QT QByteArray在串口通信中的进制转换实战:十进制与十六进制的灵活应用
下一篇: C# DataGridView 列自定义功能实战:保存与恢复用户个性化视图
cuda7parallel
博客等级 码龄1天 0粉丝 1273原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值