程序人生 | C语言字节对齐问题详解 - 对齐/字节序/位序/网络序等(下)

序列化、字节对齐、字节序(C++) 记录下自己对这3个问题的理解,C++编程方式下 字节对齐,存在的意义:是因为C++下,写网络协议的时候,经常写成struct或类class,类似于下边 struct _arp{          unsigned short      arp_hrd;          unsigned short      arp_pro;          unsigned char 阅读详情

本文首发于 2014-07-21 15:35:30

6. 附录

6.1. 字节序与网络序

6.1.1. 字节序

字节序,顾名思义就是字节的高低位存放顺序。

对于单字节,大部分处理器以相同的顺序处理比特位,因此单字节的存放和传输方式一般相同。

对于多字节数据,如整型(32位机中一般占4字节),在不同的处理器的存放方式主要有两种(以内存中 0x0A0B0C0D 的存放方式为例)。

6.1.1.1. 大字节序(Big-Endian,又称大端序或大尾序)

在计算机中,存储介质以下面方式存储整数 0x0A0B0C0D,则称为大字节序:

数据以8bit为单位:
低地址方向 -> 0x0A 0x0B 0x0C 0x0D -> 高地址方向

数据以16bit为单位:
低地址方向 -> 0x0A0B 0x0C0D -> 高地址方向

其中,最高有效位(MSB,Most Significant Byte)0x0A存储在最低的内存地址处。下个字节0x0B存在后面的地址处。同时,最高的16bit单元0x0A0B存储在低位。

简而言之,大字节序就是高字节存入低地址,低字节存入高地址。

这里讲个词源典故:“endian”一词来源于乔纳森·斯威夫特的小说《格列佛游记》。小说中,小人国为水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开而争论,争论的双方分别被称为 Big-endians 和 Little-endians 。

1980年,Danny Cohen在其著名的论文"On Holy Wars and a Plea for Peace"中为平息一场关于字节该以什么样的顺序传送的争论而引用了该词。

借用上面的典故,想象一下要把熟鸡蛋旋转着稳立起来,大头(高字节)肯定在下面(低地址)_

6.1.1.2. 小字节序(Little-Endian,又称小端序或小尾序)

在计算机中,存储介质以下面方式存储整数 0x0A0B0C0D 则称为小字节序:

数据以8bit为单位:
高地址方向 -> 0x0A 0x0B 0x0C 0x0D -> 低地址方向

数据以16bit为单位:
高地址方向 -> 0x0A0B 0x0C0D -> 低地址方向

其中,最低有效位(LSB,Least Significant Byte)0x0D存储在最低的内存地址处。后面字节依次存在后面的地址处。同时,最低的16bit单元0x0A0B存储在低位。

可见,小字节序就高字节存入高地址,低字节存入低地址。

C语言中的位域结构也要遵循比特序(类似字节序) 。例如:

struct bitfield{
    unsigned char a: 2;
    unsigned char b: 6;
}

该位域结构占1个字节,假设赋值a=0x01和b=0x02,则大字节机器上该字节为(01)(000010),小字节机器上该字节为(000010)(01) 。因此在编写可移植代码时,需要加条件编译。

注意,在包含位域的C结构中,若位域A在位域B之前定义,则位域A所占用的内存空间地址低于位域B所占用的内存空间。

另见以下联合体,在小字节机器上若low=0x01,high=0x02,则hex=0x21:

int main(void){
    union{
        unsigned char hex;
        struct{
            unsigned char low  : 4;
            unsigned char high : 4;
        };
    }convert;
    convert.low = 0x01;
    convert.high = 0x02;
    printf("hex = 0x%0x\n", convert.hex);
    return 0;
}
6.1.1.3. 注意事项

无论是大字节序,还是小字节序,变量的地址都等于变量所占字节中的低地址。 例如,下述程序中,小字节序输出 0x0D,大字节序输出 0x0A 。

 int32_t a = 0x0A0B0C0D;
 printf("0x%0x\n", *((int8_t*)&dwData));

6.1.2. 网络序

网络传输一般采用大字节序,也称为网络字节序或网络序。IP协议中定义大字节序为网络字节序。

对于可移植的代码来说,将接收的网络数据转换成主机的字节序是必须的,一般会有成对的函数用于把网络数据转换成相应的主机字节序或反之(若主机字节序与网络字节序相同,通常将函数定义为空宏)。

伯克利socket API定义了一组转换函数,用于16和32位整数在网络序和主机字节序之间的转换。htonl、htons用于主机序转换到网络序;ntohl、ntohs用于网络序转换到本机序。

注意:在大小字节序转换时,必须考虑待转换数据的长度(如5.1.1节的数据单元)。另外对于单字符或小于单字符的几个bit数据,是不必转换的,因为在机器存储和网络发送的一个字符内的bit位存储顺序是一致的。

6.1.3. 位序

用于描述串行设备的传输顺序。一般硬件传输采用小字节序(先传低位),但I2C协议采用大字节序。网络协议中只有数据链路层的底端会涉及到。

6.1.4. 处理器字节序

不同处理器体系的字节序如下所示:

  • X86、MOS Technology 6502、Z80、VAX、PDP-11 等处理器为 Little endian;
  • Motorola 6800、Motorola 68000、PowerPC 970、System/370、SPARC(除V9外) 等处理器为 Big endian;
  • ARM、PowerPC (除PowerPC 970外)、DEC Alpha,SPARC V9,MIPS,PA-RISC and IA64 等的字节序是可配置的。

6.1.5. 字节序编程

请看下面的语句:

printf("%c\n", *((short*)"AB") >> 8);

在大字节序下输出为’A’,小字节序下输出为’B’。

下面的代码可用来判断本地机器字节序:

//字节序枚举类型
typedef enum{
    ENDIAN_LITTLE = (INT8U)0X00,
    ENDIAN_BIG    = (INT8U)0X01
}E_ENDIAN_TYPE;
 
E_ENDIAN_TYPE GetEndianType(VOID)
{
    INT32U dwData = 0x12345678;
    
    // 取数都从低地址开始访问
    if(0x78 == *((INT8U*)&dwData))
        return ENDIAN_LITTLE;
    else
        return ENDIAN_BIG;
}
 
//Start of GetEndianTypeTest//
#include <endian.h>
VOID GetEndianTypeTest(VOID)
{
#if _BYTE_ORDER == _LITTLE_ENDIAN
    printf("[%s]<Test Case> Result: %s, EndianType = %s!\n", __FUNCTION__, 
           (ENDIAN_LITTLE != GetEndianType()) ? "ERROR" : "OK", "Little");
#elif _BYTE_ORDER == _BIG_ENDIAN
    printf("[%s]<Test Case> Result: %s, EndianType = %s!\n", __FUNCTION__, 
           (ENDIAN_BIG != GetEndianType()) ? "ERROR" : "OK", "Big");
#endif
}
//End of GetEndianTypeTest//

在字节序不同的平台间的交换数据时,必须进行转换。比如对于int类型,大字节序写入文件:

int i = 100;
write(fd, &i, sizeof(int));

小字节序读出后:

int i;
read(fd, &i, sizeof(int));
char buf[sizeof(int)];
memcpy(buf, &i, sizeof(int));
for(i = 0; i < sizeof(int); i++)
{
    int v = buf[sizeof(int) - i - 1];
    buf[sizeof(int) - 1] =  buf[i];
    buf[i] = v;
}
memcpy(&i, buf, sizeof(int));

上面仅仅是个例子。在不同平台间即使不存在字节序的问题,也尽量不要直接传递二进制数据。作为可选的方式就是使用文本来交换数据,这样至少可以避免字节序的问题。

很多的加密算法为了追求速度,都会采取字符串和数字之间的转换,在计算完毕后,必须注意字节序的问题,在某些实现中可以见到使用预编译的方式来完成,这样很不方便,如果使用前面的语句来判断,就可以自动适应。

字节序问题不仅影响异种平台间传递数据,还影响诸如读写一些特殊格式文件之类程序的可移植性。此时使用预编译的方式来完成也是一个好办法。

6.2. 对齐时的填充字节

代码如下:

struct A{ 
    char  c; 
    int   i; 
    short s;
};

int main(void){  
    struct A a; 
    a.c = 1; a.i = 2; a.s = 3;
    printf("sizeof(A)=%d\n", sizeof(struct A));
    return 0;
}

执行后输出为sizeof(A)=12。

6.3. pragma pack语法说明

#pragma pack(n)
#pragma pack(push, 1)
#pragma pack(pop)

1)#pragma pack(n)

该指令指定结构和联合成员的紧凑对齐。而一个完整的转换单元的结构和联合的紧凑对齐由/Zp选项设置。紧凑对齐用pack编译指示在数据说明层设置。该编译指示在其出现后的第一个结构或者联合声明处生效。该编译指示对定义无效。

当使用#pragma pack (n) 时,n 为1、2、4、8或16。第一个结构成员后的每个结构成员都被存储在更小的成员类型或n字节界限内。如果使用无参量的#pragma pack,结构成员被紧凑为以/Zp指定的值。该缺省/Zp紧凑值为/Zp 8。

2)编译器也支持以下增强型语法:

#pragma  pack( [ [ { push | pop } , ] [identifier, ] ] [ n] )

若不同的组件使用 pack编译指示 指定不同的紧凑对齐, 这个语法允许你把程序组件组合为一个单独的转换单元。

带push参量的 pack编译指示 的每次出现将当前的紧凑对齐存储到一个内部编译器堆栈中。编译指示的参量表从左到右读取。如果使用push,则当前紧凑值被存储起来;如果给出一个n值,该值将成为新的紧凑值。若指定一个标识符,即选定一个名称,则该标识符将和这个新的的紧凑值联系起来。

带一个pop参量的 pack编译指示 的每次出现都会检索内部编译器堆栈顶的值,并使该值为新的紧凑对齐值。如果使用pop参量且内部编译器堆栈是空的,则紧凑值为命令行给定的值,并将产生一个警告信息。若使用pop且指定一个n值,该值将成为新的紧凑值。

若使用pop且指定一个标识符,所有存储在堆栈中的值将从栈中删除,直到找到一个匹配的标识符。这个与标识符相关的紧凑值也从栈中移出,并且这个仅在标识符入栈之前存在的紧凑值成为新的紧凑值。如果未找到匹配的标识符, 将使用命令行设置的紧凑值,并且将产生一个一级警告。缺省紧凑对齐为8。

pack编译指示 的新的增强功能让你在编写头文件时,确保在遇到该头文件的前后的紧凑值是一样的。

6.4. Intel关于内存对齐的说明

以下内容节选自《Intel Architecture 32 Manual》。

字、双字和四字在自然边界上不需要在内存中对齐。(对于字、双字和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。)

无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。

一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。

某些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。双四字的自然边界是能够被16整除的地址。其他操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。

6.5. 不同架构处理器的对齐要求

RISC指令集处理器(MIPS/ARM):这种处理器的设计以效率为先,要求所访问的多字节数据(short/int/long)的地址必须是此数据大小的倍数,如short数据地址应为2的倍数,long数据地址应为4的倍数,也就是说是对齐的。

CISC指令集处理器(X86) :没有上述限制。

对齐处理策略

访问非对齐多字节数据时(pack数据),编译器会将指令拆成多条(因为非对齐多字节数据可能跨越地址对齐边界),保证每条指令都从正确的起始地址上获取数据,但也因此效率比较低。

访问对齐数据时则只用一条指令获取数据,因此对齐数据必须确保其起始地址是在对齐边界上。如果不是在对齐的边界,对X86 CPU是安全的,但对MIPS/ARM这种RISC CPU会出现总线访问异常。

为什么X86是安全的呢?

X86 CPU是如何进行数据对齐的?

X86 CPU的EFLAGS寄存器中包含一个特殊的位标志,称为AC(对齐检查的英文缩写)标志。

按照默认设置,当CPU首次加电时,该标志被设置为0。

当该标志是0时,CPU能够自动执行它应该执行的操作,以便成功地访问未对齐的数据值。

然而,如果该标志被设置为1,每当系统试图访问未对齐的数据时,CPU就会发出一个INT 17H中断。

X86的Windows 2000和Windows 98版本从来不改变这个CPU标志位。因此,当应用程序在X86处理器上运行时,你根本看不到应用程序中出现数据未对齐的异常条件。

为什么MIPS/ARM不安全呢?

因为MIPS/ARM CPU不能自动处理对未对齐数据的访问。当未对齐的数据访问发生时,CPU就会将这一情况通知操作系统。这时,操作系统将会确定它是否应该引发一个数据未对齐异常条件,对vxworks是会触发这个异常的。

6.6. ARM下的对齐处理

有部分摘自ARM编译器文档对齐部分。

对齐的使用:

  1. __align(num) 用于修改最高级别对象的字节边界。
  • 在汇编中使用LDRD或STRD时就要用到此命令__align(8)进行修饰限制。来保证数据对象是相应对齐。
  • 这个修饰对象的命令最大是8个字节限制,可以让2字节的对象进行4字节对齐,但不能让4字节的对象2字节对齐。
  • __align是存储类修改,只修饰最高级类型对象,不能用于结构或者函数对象。
  1. __packed 进行一字节对齐。需注意:
  • 不能对packed的对象进行对齐;
  • 所有对象的读写访问都进行非对齐访问;
  • float及包含float的结构联合及未用__packed的对象将不能字节对齐;
  • __packed对局部整型变量无影响。
  • 强制由unpacked对象向packed对象转化时未定义。整型指针可以合法定义为packed,如__packed int* p(__packed int 则没有意义)

对齐或非对齐读写访问可能存在的问题:

//定义如下结构,b的起始地址不对齐。在栈中访问b可能有问题,因为栈上数据对齐访问
__packed struct STRUCT_TEST{
    char a;
    int  b;
    char c;
};

//将下面的变量定义成全局静态(不在栈上)
static char *p;
static struct STRUCT_TEST a;

void main(){
    __packed int *q; //定义成__packed来修饰当前q指向为非对齐的数据地址下面的访问则可以
    p = (char*)&a; 
    q = (int*)(p + 1); 
    *q = 0x87654321;

    /* 得到赋值的汇编指令很清楚
    ldr      r5,0x20001590 ; = #0x12345678
    [0xe1a00005]   mov     r0,r5
    [0xeb0000b0]   bl      __rt_uwrite4  //在此处调用一个写4字节的操作函数
    [0xe5c10000]   strb    r0,[r1,#0]    //函数进行4次strb操作然后返回,正确访问数据
    [0xe1a02420]   mov     r2,r0,lsr #8
    [0xe5c12001]   strb    r2,[r1,#1]
    [0xe1a02820]   mov     r2,r0,lsr #16
    [0xe5c12002]   strb    r2,[r1,#2]
    [0xe1a02c20]   mov     r2,r0,lsr #24
    [0xe5c12003]   strb    r2,[r1,#3]
    [0xe1a0f00e]   mov     pc,r14
    
    若q未加__packed修饰则汇编出来指令如下(会导致奇地址处访问失败):
    [0xe59f2018]   ldr      r2,0x20001594 ; = #0x87654321
    [0xe5812000]   str     r2,[r1,#0]
    */
    //这样很清楚地看到非对齐访问如何产生错误,以及如何消除非对齐访问带来的问题
    //也可看到非对齐访问和对齐访问的指令差异会导致效率问题
}

6.7. 《The C Book》之位域篇

While we’re on the subject of structures, we might as well look at bitfields. They can only be declared inside a structure or a union, and allow you to specify some very small objects of a given number of bits in length. Their usefulness is limited and they aren’t seen in many programs, but we’ll deal with them anyway. This example should help to make things clear:

struct{
    unsigned field1 :4; //field 4 bits wide
    unsigned        :3; //unnamed 3 bit field(allow for padding)
    signed field2   :1; //one-bit field(can only be 0 or -1 in two's complement)
    unsigned        :0; //align next field on a storage unit
    unsigned field3 :6;
}full_of_fields;

Each field is accessed and manipulated as if it were an ordinary member of a structure. The keywords signed and unsigned mean what you would expect, except that it is interesting to note that a 1-bit signed field on a two’s complement machine can only take the values 0 or -1. The declarations are permitted to include the const and volatile qualifiers.

The main use of bitfields is either to allow tight packing of data or to be able to specify the fields within some externally produced data files. C gives no guarantee of the ordering of fields within machine words, so if you do use them for the latter reason, you program will not only be non-portable, it will be compiler-dependent too. The Standard says that fields are packed into ‘storage units’, which are typically machine words. The packing order, and whether or not a bitfield may cross a storage unit boundary, are implementation defined. To force alignment to a storage unit boundary, a zero width field is used before the one that you want to have aligned.

Be careful using them. It can require a surprising amount of run-time code to manipulate these things and you can end up using more space than they save.

Bit fields do not have addresses—you can’t have pointers to them or arrays of them.

6.8. C语言字节相关面试题

6.8.1. Intel/微软C语言面试题

请看下面的问题:

#pragma pack(8)
struct s1{
    short a; // 按 min(1,8) 对齐
    long  b; // 按 min(4,8) 对齐
};
struct s2{
    char c;
    s1   d;
    long long e;  //VC6.0下可能要用__int64代替双long
};
#pragma pack()

问题:

  1. sizeof(s2) = ?
  2. s2的s1中的a后面空了几个字节接着是b?

分析:

成员对齐有一个重要的条件,即每个成员分别按自己的方式对齐。

也就是说上面虽然指定了按8字节对齐,但并不是所有的成员都是以8字节对齐。其对齐的规则是:每个成员按 其类型的对齐参数(通常是这个类型的大小) 和 指定对齐参数(这里是8字节) 中较小的一个对齐,并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。

s1中成员a是1字节,默认按1字节对齐,而指定对齐参数为8,两值中取1,即a按1字节对齐;成员b是4个字节,默认按4字节对齐,这时就按4字节对齐,所以sizeof(s1)应该为8;

s2中c和s1中a一样,按1字节对齐。而d是个8字节结构体,其默认对齐方式就是所有成员使用的对齐参数中最大的一个,s1的就是4。所以,成员d按4字节对齐。成员e是8个字节,默认按8字节对齐,和指定的一样,所以它对到8字节的边界上。这时,已经使用了12个字节,所以又添加4个字节的空,从第16个字节开始放置成员e。此时长度为24,并可被8(成员e按8字节对齐)整除。这样,一共使用了24个字节。

各个变量在内存中的布局为:

c***aa**
bbbb****
dddddddd ——这种“矩阵写法”很方便看出结构体实际大小!

因此,sizeof(S2)结果为24,a后面空了2个字节接着是b。

这里有三点很重要:

  1. 每个成员分别按自己的方式对齐,并能最小化长度;
  2. 复杂类型(如结构)的默认对齐方式是其最长的成员的对齐方式,这样在成员是复杂类型时可以最小化长度;
  3. 对齐后的长度必须是成员中最大对齐参数的整数倍,这样在处理数组时可保证每一项都边界对齐。

还要注意,“空结构体”(不含数据成员)的大小为1,而不是0。试想如果不占空间的话,一个空结构体变量如何取地址、两个不同的空结构体变量又如何得以区分呢?

6.8.2 上海网宿科技面试题

假设硬件平台是intel x86(little endian),以下程序输出什么:

//假设硬件平台是intel x86(little endian)
typedef unsigned int uint32_t; 
void inet_ntoa(uint32_t in){
    char  b[18];
    register  char  *p;
    p = (char *)∈
#define UC(b) (((int)b)&0xff) //byte转换为无符号int型
    sprintf(b, "%d.%d.%d.%d\n", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
    printf(b);
}

int main(void){  
    inet_ntoa(0x12345678);
    inet_ntoa(0x87654321);
    return 0;
}

先看如下程序:

int main(void){  
    int a = 0x12345678;
    char *p = (char *)&a;
    char str[20];
    sprintf(str,"%d.%d.%d.%d\n", p[0], p[1], p[2], p[3]);
    printf(str);
    return 0;
}

按照小字节序的规则,变量a在计算机中存储方式为:

高地址方向 --------------> 低地址方向
0x12 0x34 0x56 0x78
p[3] p[2] p[1] p[0]

注意:p并不是指向0x12345678的开头0x12,而是指向0x78。p[0]到p[1]的操作是&p[0]+1,因此p[1]地址比p[0]地址大。输出结果为120.86.52.18。

反过来的话,令int a = 0x87654321,则输出结果为33.67.101.-121。

为什么有负值呢?

因为系统默认的char是有符号的,本来是0x87也就是135,大于127因此就减去256得到-121。

想要得到正值的话只需将char *p = (char *)&a改为unsigned char *p = (unsigned char *)&a即可。

综上不难得出,网宿面试题的答案为120.86.52.18和33.67.101.135。

说明:
本文转载自 https://www.cnblogs.com/clover-toeic/p/3853132.html


欢迎关注我的微信公众号【数据库内核】:分享主流开源数据库和存储引擎相关技术。

标题网址
GitHubhttps://dbkernel.github.io
知乎https://www.zhihu.com/people/…
思否(SegmentFault)https://segmentfault.com/u/db…
掘金https://juejin.im/user/5e9d3e…
开源中国(oschina)https://my.oschina.net/dbkernel
博客园(cnblogs)https://www.cnblogs.com/dbkernel
网络字节序之大小端(字节序与比特序) 引言:最近在网上看了很多博客,想要深入了解大小端问题,主要是做毕设时,RTP包协议的结构体定义有两种方式,即大端和小端。但是一些博客并没有讲到理解大小端的本质问题,在这里按自己的理解扩充一下,可能有错,望理解!!! 1. 字节序 字节序即字节的存储顺序,如果数据都是单字节的,那怎么存储无所谓了,但是对于多字节数据,比如int,double等,就要考虑存储的顺序了。字节序是硬... 阅读详情

相关推荐

【C语言 | 嵌入式】大端序和小端序详解

字节序 字节序,又称端序,英文Endiannnes。字节序,简单点说,就是字节的存储顺序。数据都是单字节,那么不存在字节的存储顺序,对于多字节的数据,就要考虑字节的存储顺序了。典型的情况是int、double等在内存中的存放方式和网络传输的传输顺序。 字节序跟硬件的体系结构有关,和编程语言以及操作系统无关,例如在x86系列的pc上的solaris系统是小端序,sunsparc平台的solaris是大端序。 大端序(Big-endian) 大端字节序,高字节存于内存低地址,低字节存于内存高地址。 小端序

萧邯嵌入式笔记 5585

C语言----字节对齐

C语言字节对齐

ftzchina的博客 5571

c语言关键字_ _align()和_ _packed的使用以及字节对齐原理

字节对齐(Byte Alignment)是计算机内存中的一种存储优化技术,用于确保数据在内存中的存储位置满足特定的硬件要求,以提高内存访问的效率。在现代计算机体系结构中,许多处理器要求数据以特定的方式对齐,以便在访问内存时能够更快地读取数据。字节对齐的原则是确保特定数据类型的起始地址是它自身大小的倍数。如果数据没有按照正确的对齐方式存储在内存中,处理器在访问这些数据时可能需要额外的操作来解决不对齐的情况,从而增加了访问数据的时间和计算开销。

Known668的博客 3082

C语言字节对齐详解

现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序一个接一个地存放,这就是对齐。有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可。为了节省存储空间和处理简便,C语言提供了一种数据结构,称为“位域”或“位段”。

Magicamazing的博客 2180

DIY音频必备:手把手教你用AB类功放模块打造高保真桌面音响(含电路图)

本文详细指导如何利用AB类功放模块DIY高保真桌面音响,涵盖选型指南、核心元器件清单、电路搭建与焊接工艺,以及系统调试与音质优化技巧。AB类功放以其接近A类功放的音质和B类功放的效率,成为音频爱好者的理想选择,适合有一定电子基础的实践者。

weixin_42665725的博客 445

Halcon阈值算子 -- 局部阈值之dyn_threshold

Halcon阈值算子 – dyn_threshold HALCON有很多阈值算子,接下来将一一介绍。本文先介绍dyn_threshold。 以下介绍主要参考HALCON帮助文档,并加上自己的体会。如有纰漏,欢迎留言指出 理论介绍 dyn_threshold算子的函数签名如下: dyn_threshold(OrigImage, ThresholdImage : RegionDynThresh : Offset, LightDark : ) 输入参数有: OrigImage:待处理图像 ThresholdIm

m0_47015717的博客 5386

清晰解读C语言中的位域、字节序、比特序、大小端

一、比特序/位序 比特序表示一个字节中8个比特位(bit)之间的顺序问题。分为LSB 0 位序和MSB 0 位序。 LSB(least significant bit):数据的最低位存放在字节的第0位。 MSB (most significant bit):数据的最高位存放在字节的第0位。 例如有一个十进制的数为174,对应的二进制数为1010 1110. 1.在LSB 0 位序下,其存储形式如下图: 数据流的顺序为0-1-1-1-0-1-0-1 2.在MSB 0 位序下,其存储形式如下图: 数

qq_34907757的博客 5732

Prokka实战:10分钟搞定细菌基因组注释(附详细参数解析)

本文深入解析Prokka细菌基因组注释工具的核心参数与实战策略。通过拆解其集成化工作流程,详细解读物种分类、功能注释、输出控制等关键参数,并提供快速初筛、高质量发表、质粒注释及批量处理四种典型场景的高效参数组合方案,帮助用户精准掌控注释过程,将原始序列转化为有价值的生物学见解。

weixin_29271053的博客 444

字节对齐和字节序

1、什么是字节对齐内存空间是按字节划分,理论上可以从任意起始地址访问任意类型的变量。但实际上在访问特定类型变量是经常在特定的内存地址访问,这就需要各种数据类型按照一定的规则进行排列,而不是一个接一个紧接着排放。例如32位的计算机处理器通过总线访问内存数据。每个总线周期从偶地址开始访问32位数据,如果一个32位的数据没有存放在4字节整除的内存地址处,那么处理器就需要两个总线周期对其进行访问,显然会降低访问效率。因此,通过合理的内存对齐可以提高访问效率。

qq_33411015的博客 727

先进封装技术的一些优缺点探讨

半导体封装技术是半导体制造过程中的关键环节,它不仅保护了芯片免受物理损伤,还提供了电气连接和散热功能。随着技术的发展,出现了多种先进的封装技术,每种技术都有其特定的应用场景和优缺点。

阿拉伯梳子的专栏 2172

【吃瓜教程】周志华西瓜书课后习题第一章答案

第一章 1.1表1.1中若只包含编号为1和4的两个样例,试给出相应的版本空间。 编号 色泽 根蒂 敲声 好瓜(标记) 1 青绿 蜷缩 浊响 是Y 4 乌黑 稍蜷 沉闷 否N 知识储备: 假设空间: 所有假设组成的空间 版本空间:与训练集一致的假设集合 从假设空间到版本空间算法大致如下: 1.删除与正例不一致的假设且删除与反例一致的假设 2.删除与正例不一致的假设 3.删除与反例一致的假设 具体选择哪种

MaxQuYY的博客 8372

程序人生 | C语言字节对齐问题详解 - 对齐/字节序/位序/网络序等(上)

考虑下面的结构体定义: 假设这个结构体的成员在内存中是紧凑排列的,且c1的起始地址是0,则s的地址就是1,c2的地址是3,i的地址是4。现在,我们编写一个简单的程序: 运行后输出: 为什么会这样?这就是字节对齐导致的问题。本文在参考诸多资料的基础上,详细介绍常见的字节对齐问题。因成文较早,资料来源大多已不可考,敬请谅解。现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量,但实际上在访问特定类型变量时经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是一

dbkernel 的博客 1435

IEC 60747-8 是由国际电工委员会(IEC)制定的标准,标题为《半导体器件 - 分立器件 - 第8部分:场效应晶体管》

IEC 60747-8 是由国际电工委员会(IEC)制定的标准,标题为《半导体器件 - 分立器件 - 第8部分:场效应晶体管》(Semiconductor devices - Discrete devices - Part 8: Field-effect transistors)。该标准详细规定了场效应晶体管(FETs)的测试方法,涵盖静态和动态特性测试,适用于多种类型的FET,包括结型场效应晶体管(JFETs)、绝缘栅场效应晶体管(MOSFETs,增强型和耗尽型)等。3. 标准其他部分(简要概述)

专注于前沿技术的探索与实践,热衷于从代码逻辑、架构设计到行业应用等多维度深挖技术本质。期待在技术之路上与你共同成长~ 577

深入理解字节对齐

C语言--字节对齐基础知识了解一、操作系统位数、CPU位数、指令集1.操作系统--32-bit(x86)和64-bit(x64)(1)位数(2)64-bit2.处理器CPU位数3.CPU指令集4.寄存器5.关系6.计算机字长(机器字长)7.总结理解字节对齐二、字节对齐1.什么是字节对齐?2.为什么要字节对齐①首先,不同硬件平台对存储空间的处理上存在不同;②根本原因在于CPU访问数据的效率问题;③其...

CharlesJhonson的博客 2万+

基于YOLOv8的水果新鲜程度检测系统设计与实现

数据采集与预处理模块:负责收集水果图像数据并进行标注和增强深度学习模型:基于YOLOv8的目标检测模型新鲜度评估模块:根据检测结果评估水果新鲜程度用户界面:提供友好的交互界面系统集成:将各模块整合为完整系统水果新鲜程度检测需要包含多种水果在不同新鲜度状态下的图像数据集。:包含5种常见水果(苹果、香蕉、橙子、葡萄、草莓)在不同新鲜度下的图像包含约8,000张图像,分为新鲜和腐烂两类AgriVision:大型农业图像数据集,包含水果检测和分类任务Fruit-360:包含120种水果的高质量图像。

YOLO 445

[dprecated]第五章:TTM分析: 5.1 TTM设计目标和核心概念

TTM是Linux DRM框架下的通用显存管理模块,其复杂性源于需要满足多样化的显存管理需求。该文解析了TTM的核心结构体及其关系:ttm_device作为顶层管理者,包含多个ttm_resource_manager处理不同类型内存;ttm_buffer_object为核心对象,通过ttm_resource关联物理资源;其他组件如ttm_tt管理页表、ttm_pool优化分配效率。文章强调理解这些结构体关系是掌握TTM机制的基础,并建议国产芯片开发者参考这些功能需求。

图形/计算GPU的驱动与虚拟化技术分享园地 2130

字节对齐_大小端_位序

字节序 字节序,顾名思义就是字节的高低位存放顺序。1 对于单字节,大部分处理器以相同的顺序处理比特位,因此单字节的存放和传输方式一般相同。 对于多字节数据,如整型(32位机中一般占4字节),在不同的处理器的存放方式主要有两种(以内存中0x0A0B0C0D的存放方式为例)。 大端,Big-Endian 在计算机中,存储介质以下面方式存储整数0x0A0B0C0D则称为大字节序: 0x0A 0xOB 0xOC 0xOD 0x0000 0x0001 0x0002 0x0003 其中,最高有效位(

lkzp12的博客 1069

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C语言字节对齐问题详解(对齐、字节序、网络序等)

阅读目录 引言 一  什么是字节对齐 二  对齐的原因和作用 三  对齐的分类和准则 3.1 结构体对齐 3.2 栈内存对齐 3.3 位域对齐 四  总结 五  附录 5.1 字节序与网络序 5.2 对齐时的填充字节 5.3 pragma pack语法说明 5.4 Intel关于内存对齐的说明 5.5 不同架构处理器的对齐要求 5.6 ARM下的对齐...

liangxiaoxi7的博客 1016

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

什么是字节序(端序、低端字节序、高端字节序、网络字节序)

字符串12在内存中的第一个字节到底是什么?本篇文章将详细解释字节序、比特序与端序的概念。

qq_30576521的博客 6068

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

CAN总线位序与字节序

字节序(Byte Order)是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。在计算机中是以字节为单位,每个地址对应一个字节,一个字节8bit。在C中,除了8bit的char以外,还有16bit的short,32位的int,64位long,当然具体要由编译器决定,可以通过sizeof来获取不同类型在内存中占用的字节数。在计算机系统中,当物理单位的长度大于1个字节时,就要区分字节顺序。

April的博客 1万+

C语言字节对齐问题详解

    引言      考虑下面的结构体定义: 1 typedef struct{ 2 char c1; 3 short s; 4 char c2; 5 int i; 6 }T_FOO;      假设这个结构体的成员在内存中是紧凑排列的,且c1的起始地址是0,则s的地址就是1,c2的地址是3,i的地址是4。      现在,...

weixin_34367845的博客 1444

C语言字节对齐

字节对齐(Byte Alignment)是指数据在内存中的存储地址需要按照特定规则对齐。在计算机体系结构中,内存通常按照字(word)为单位进行访问,而字的大小取决于具体的硬件平台(如32位系统中通常为4字节,64位系统中通常为8字节)。为了提高内存访问效率,编译器会根据数据类型和平台特性自动进行内存对齐。

Made In SQL 851

字节序以及C语言struct中的位域

大端序(BE, Big-Endian):高字节在前,低字节在后(高字节存放在低地址,低字节存放在高地址)。 小端序(LE, Little-Endian):低字节在前,高字节在后(低字节存放在低地址,高字节存放在高地址)。 大小端设备上给struct位域成员分配的位存储空间与单字节数值中的bit位的对应关系为: 1)小端:先从单字节数值中的LSB开始分配; 2)大端:先从单字节数值中的MSB开始分配; 单字节内,大端的位域定义和小端的位域定义顺序相反时,代表了相同的结构体定义。

BitSwimmer的博客 4193

关于C/C++字节对齐、位域、大小端、柔性数组问题

一、字节对齐 1.概念 字节按照特定的规则在空间上的排列。 2.原则 ①成员变量的顺序会影响结构体的大小。 一般情况下,成员变量所占用的空间,会被其中最宽变量类型所框定,而当定义小于最宽类型的成员变量时,这个变量会和相邻的成员变量合并,拼为成员变量的整数倍形式,如果相邻处没有合适的变量,它将自身占有最宽类型成员变量存储空间大的大小。 ②结构体大小是最宽字节类型的整数倍 当用上述规则束...

789

为什么你的二进制文件读写出错了?深度剖析C语言位域字节序与对齐问题

解决C语言位域读写异常,深入解析二进制文件操作中的字节序与内存对齐问题。涵盖嵌入式、协议解析等场景,揭示跨平台数据存储兼容性关键点,提供可靠位域设计方法。掌握这些技巧,避免数据解析错误,值得收藏。

CompiGlow的博客 1040

大端,小端;网络序,主机序

在网络编程中,特别是底层网卡驱动开发时,常常遇到字节序问题。字节序指的是多字节数据类型在内存中存放的顺序,高位保存在低地址还是高地址,以此来划分大端还是小端。

weixin_38184628的博客 2512
上一篇: 程序人生 | UNIX环境高级编程技巧之 du 指令实现
下一篇: 系统运维 | Ubuntu 下安装配置 samba 服务的详细过程
dbkernel
博客等级 码龄4年 60粉丝 42原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值