显示12个字节

本文深入探讨了字符编码原理及不同编码方式下字符占用空间的变化,并解析了字符在不同字体和字号设置下屏幕显示宽度的区别。
如果你看到这篇文章的标题,隐约或者明确觉得不对劲儿。那,恭喜你!你知道我接下来要说什么了。 听我们的PM 美眉和研发同事在讨论问题,PM说到: “这里展示12个字节”。我一听怎么那么别扭呢?然后就问PM同事说怎么怎么回事。然后PM同事说是这么这么回事。(此处省略若干字……)最终确定这就是一个混沌的说法。因为当时我们的PM和研发同事都没有弄明白下面两个问题。才会产生这样的说法(和做法)。
  1. 中英文(不同编码)间,每个字符存储起来占用的空间不一样
  2. 中英文(不同字符)间,每个字符显示出来占用的宽度不一样
先说第一个问题。上面说的也还是比较笼统的。更加严谨的说法应该是, 同一个字符,采用不同的编码方式表示所占用的空间是可能不一样的比如:
System.out.println(Arrays.toString("东".getBytes(Charset.forName("UTF-8")))); // [-28, -72, -100]
System.out.println(Arrays.toString("东".getBytes(Charset.forName("GBK")))); // [-74, -85]
同样东东的的“东”字,用UTF-8编码表示,占用了3个字节的长度,用GBK编码表示,占用了两个字节的长度。 同一种编码方式,表示不同的字符所占用的空间也是可能不一样的。比如:
System.out.println(Arrays.toString("东".getBytes(Charset.forName("GBK")))); // [-74, -85]
System.out.println(Arrays.toString("D".getBytes(Charset.forName("GBK")))); // [68]
同样是GBK编码,表示“东”字用了2个字节,而表示大写字母“D”则只用了1个字节。这恐怕就是 流毒无穷的“ 一个中文字符算两个长度”说法的来源了。别再这样说,这是错的!如果你用的UTF-8编码,则可能是一个中文占3个甚至4个长度! 如果你用的Oracle数据库,相信会有一定的体会。Oracle对varchar类型的字段长度是按照 字节来指定的。所以一个长度为100的varchar字段,最多能存储一个str.length()==100的英文字符串。却只能存储str.length()==50(GBK编码)或str.length()==33(UTF-8编码)的中文字符串。这时候需要在数据录入时控制长度就比较悲催了。就有人出了“ 一个中文字符算两个长度”的馊主意。正确的做法应该是使用相应的编码将字符串转换成字节数组,看字节数组的长度。遗憾的是JavaScript没有提供原生的编码解码实现。 如果你使用的是varchar2类型或者是MySQL数据库,就比较开心了。他们使用的是以字符为单位指定字段的长度。所以数据库长度为100时,前端只要str.length()<=100就一定不会超长了。 关于字符编码,可以看看 维基百科的解释。 再说第二个问题,不同的字符,显示出来占用的宽度不一样。同样,上面的说法也是比较笼统的, 一个字符在屏幕上显示的宽度,同时受字号(font-size)和字体(font-family)的影响。 先说字号。一般情况我们会写:
font-size:12px;
一个字符显示在屏幕上。是一个二维的概念,有宽度和高度,那这个12px到底是说这个字符的宽度为12px还是高度为12px呢?都不是!font-size实际上设置的是字体中字符框的高度;实际的字符字形可能比这些框高或矮(通常会矮)。
<style type="text/css">
p {font-size: 80px}
</style>

<p>aaaAAA222中中中</p>
DeepinScrot-4323   可以看到,font-size设置为80px时,中文,英文,数字的实际高度都没有超过80。具体会有多高其实不用太关心,只要知道font-size越大,展示出来的字也越大就可以了。显示上的事是一个主观感受上的事。再看宽度,同样是80px的字号,小写字母,大写字母,数字和中文占的宽度也不一样,上图应该能比较明显的看出来,就不做对比图了。 再说字体,比如:
<style type="text/css">
p {font-size: 30px}
.p1{font-family:serif}
.p2{font-family:monospace}
</style>

<p class="p1">abcdefghijklmn</p>
<p class="p2">abcdefghijklmn</p>
DeepinScrot-0503 同样的内容“abcdefghijklmn ”,同样的字号“30px”,不同的字体“serif”和“mogospace”. 所占用的宽度是不一样的。由这点可以看出用str.subString(0, n) + "..." 的方式来实现“文本超长则用省略号表示”是不靠谱的。正确的做法应该是用css在展示的时候实现。
<style type="text/css">
p {
    width:100px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
</style>

<p>我很长,我真的很长</p>
关于文本溢出问题,推荐阅读 这篇文章。其实拿大腿想想也是这样的,文本溢出是显示上的问题,按照“职责分配原则”中的“专家原则”也不能将显示的事儿交给数据处理去做。 好吧,就到这吧。希望看完这篇文章的同学不会再说出“一个中文算两个长度”和“这里显示12个字节”这样的话了。那我就功德圆满了。

转载于:https://my.oschina.net/laichendong/blog/283791

<think>好的,我现在要解决的问题是关于CAN协议中数据帧长度9字节但有效载荷只有8字节,如何解决实际数据量不匹配的问题。首先,我需要回顾一下CAN协议的基本结构,特别是数据帧的部分。根据引用[3],CAN的数据帧有效载荷最多8字节,这确实是一个限制。用户提到数据帧长度是9字节,但有效载荷只有8字节,这里可能指的是整个数据帧的某个部分,比如数据字段本身是8字节,而其他部分如ID、控制字段等占用了额外的空间,导致总长度更长。 首先,我需要确认传统CAN和CAN FD的区别。根据引用[1]和[2],传统CAN的最大有效载荷是8字节,而CAN FD支持更长的数据长度,最多64字节。所以,如果用户还在使用传统CAN,升级到CAN FD可能是一个直接的解决方案。但用户的问题可能是在传统CAN框架下如何优化,所以需要探讨在不升级协议的情况下如何处理。 可能的解决方案包括数据分帧和重组。将超过8字节的数据分割成多个帧发送,接收端再重新组合。这需要应用层协议的支持,比如在数据中添加序列号或标识符,确保接收方能正确重组。但这样会增加通信的复杂性和延迟,特别是在实时性要求高的场景下可能不太理想。 另一个方法是数据压缩。通过压缩算法减少数据体积,使其适应8字节的限制。但压缩算法需要双方都支持,且压缩率不一定可靠,可能会影响实时性。 此外,优化数据结构,比如使用更高效的编码方式(如二进制标志位代替ASCII字符),可能减少所需字节数。例如,使用位字段来表示多个布尔状态,而不是每个状态占一个字节。这需要仔细设计数据格式,确保信息不丢失。 还要考虑优先级设置。CAN总线通过ID进行仲裁,高优先级的消息优先发送。在分帧传输时,需要确保同一数据块的多个帧具有相同的优先级,避免被其他消息打断,导致重组失败。 不过,如果用户的环境允许升级协议,那么切换到CAN FD是最有效的解决方案,因为它直接支持更大的有效载荷。引用[2]提到CAN FD是CAN的升级版,弥补了数据长度和带宽的限制,有效载荷可达64字节,传输速率也更高。这对于现代车辆系统的高带宽需求更为合适。 总结可能的解决方案: 1. 分帧传输和重组(传统CAN) 2. 数据压缩(传统CAN) 3. 数据结构优化(传统CAN) 4. 升级到CAN FD(需要硬件支持) 需要评估每种方案的优缺点,根据具体应用场景选择。例如,如果系统对实时性要求高且数据量大,升级到CAN FD可能是最佳选择。如果数据量不大但偶尔超出,分帧或压缩可能更合适。 另外,用户提到的数据帧长度9字节可能是指整个数据帧的结构。传统CAN的数据帧包括帧起始、仲裁场、控制场、数据场(最多8字节)、CRC场、ACK场和帧结束。整个帧的总长度会根据位填充等因素变化,但数据场固定为0-8字节。因此,有效载荷确实只有8字节,其他部分用于协议控制,无法用于传输数据。 最后,还需要考虑错误处理机制。分帧传输时,如果某一帧丢失或出错,需要重传机制,这可能增加协议的复杂性。而CAN FD由于支持更大的数据量,减少了分帧的需要,从而降低了这种风险。</think>根据CAN协议的特性及现有解决方案,针对数据帧有效载荷限制的问题,可通过以下方法解决: ### 一、传统CAN协议下的优化方案 1. **数据分帧传输与重组** 将超过8字节的数据拆分为多个CAN帧发送,接收端按约定规则重组。例如: - 在应用层添加分帧标识(如序列号、总帧数、数据类型),例如: $$帧1: [类型ID | 序列号1/3 | 数据字节1-6]$$ $$帧2: [类型ID | 序列号2/3 | 数据字节7-12]$$ $$帧3: [类型ID | 序列号3/3 | 数据字节13-16]$$ - 需设计超时重传机制保证完整性[^3]。 2. **数据压缩与编码优化** - 使用二进制位压缩(如将8个布尔状态压缩为1字节)。 - 采用紧凑编码(如用2字节表示0~65535范围的整数,代替ASCII字符串)。 - 通过算法(如霍夫曼编码)进一步减少数据体积,但需权衡计算开销。 3. **动态数据优先级分配** 通过仲裁场ID控制分帧数据的优先级,确保同一数据块的多个帧连续发送,避免被高优先级消息打断。 --- ### 二、协议升级方案:切换至CAN FD 1. **直接扩展有效载荷** CAN FD支持最大64字节有效载荷,数据速率提升至5 Mbps(仲裁段仍为1 Mbps),可直接传输更长的数据,无需分帧[^2]。 ```c // CAN FD数据帧结构示例(简化) struct canfd_frame { uint32_t can_id; // 11/29位ID uint8_t len; // 数据长度(0-64) uint8_t data[64]; // 有效载荷 }; ``` 2. **兼容性处理** - CAN FD控制器通常兼容传统CAN设备,可逐步升级系统。 - 需注意网络混合使用时,传统CAN节点会忽略CAN FD帧。 --- ### 三、方案对比与选择建议 | 方案 | 优点 | 缺点 | 适用场景 | |---------------------|-------------------------------|-------------------------------|------------------------------| | 分帧传输 | 无需硬件升级 | 增加延迟与协议复杂度 | 数据量偶尔超限的旧系统 | | 数据压缩 | 节省带宽 | 压缩率不稳定,计算开销大 | 文本/冗余数据较多的场景 | | 升级至CAN FD | 彻底解决长度限制,带宽高 | 需硬件支持,成本较高 | 新系统或高实时性需求场景 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值