yealien 发表于 2011-6-29 20:04:45

又是结构体,又外包共用体,这是什么意思呢?

union {
      struct {
         unsigned b0:1;
         unsigned b1:1;
         unsigned b2:1;
         unsigned b3:1;
         unsigned b4:1;
         unsigned b5:1;
         unsigned b6:1;
         unsigned b7:1;
         }oneBit;
      unsigned char allBits;
       } myFlag;

以上一段例程,在结构体外面包了一层共用体,并且还定义了一个非字符变量,是个是什么意思呢?在结构体内比如:unsigned b3:1;是什么意思呢?不是赋值吧?
求各位能帮手!谢了!

reynold520 发表于 2011-6-29 20:24:15

allBits 与 onebit 共用一片内存 onebit 里面的是bit 位,不时 赋值

laujc 发表于 2011-6-29 20:30:25

这些基本的东西,应该看书的。。。

johnwjl 发表于 2011-6-29 20:39:25

模拟位操作,大多mcu的头文件都如此。

xbwpc 发表于 2011-6-29 21:00:10

c语言中的位段,楼主的C没学好

jackiezeng 发表于 2011-6-29 21:06:00

位域 和 CHAR 公用一个内存,,可以方便的操作一个位,也可以方便的得到所有位组成的这个字节的值,,

waitingconfirm 发表于 2011-6-29 21:54:37

某些在软件上学不进新东西的“老一辈”电子工程师传出来的编程臭毛病罢了

也许某些编译器可以达到“老人”们YY的目的,但换个环境甚至只是换个编译器就基本上全砸

对于 C 语言来说,位操作是有其公认的规范写法的,耍这点小聪明,最后无非害人害己罢了

bigZ 发表于 2011-6-29 22:02:19

回复【6楼】waitingconfirm
某些在软件上学不进新东西的“老一辈”电子工程师传出来的编程臭毛病罢了
也许某些编译器可以达到“老人”们yy的目的,但换个环境甚至只是换个编译器就基本上全砸
对于 c 语言来说,位操作是有其公认的规范写法的,耍这点小聪明,最后无非害人害己罢了
-----------------------------------------------------------------------

汗流浃背的。。。。

jackiezeng 发表于 2011-6-29 22:06:09

回复【6楼】waitingconfirm
某些在软件上学不进新东西的“老一辈”电子工程师传出来的编程臭毛病罢了
也许某些编译器可以达到“老人”们yy的目的,但换个环境甚至只是换个编译器就基本上全砸
对于 c 语言来说,位操作是有其公认的规范写法的,耍这点小聪明,最后无非害人害己罢了
-----------------------------------------------------------------------

想听听这位大侠的高见,,,,,,,,,,,,,,,,,,,

skyhu 发表于 2011-6-29 22:08:57

回复【6楼】waitingconfirm
-----------------------------------------------------------------------

你真的很臭屁

niba 发表于 2011-6-29 22:09:20

怎么引用位变量呢?

jackiezeng 发表于 2011-6-29 22:14:25

回复【10楼】niba
怎么引用位变量呢?

-----------------------------------------------------------------------

myflag.onebit.b1

Cliff 发表于 2011-6-29 23:18:22

回复【6楼】waitingconfirm
某些在软件上学不进新东西的“老一辈”电子工程师传出来的编程臭毛病罢了
也许某些编译器可以达到“老人”们yy的目的,但换个环境甚至只是换个编译器就基本上全砸
对于 c 语言来说,位操作是有其公认的规范写法的,耍这点小聪明,最后无非害人害己罢了
-----------------------------------------------------------------------

位操作?公认?小聪明?
那我问你:
union {
      struct {
         unsigned b0_3:4;
         unsigned b4_6:3;
         unsigned b7:1;
         }oneBit;
      unsigned char allBits;
       } myFlag;
这是位操作吗?

不要告诉我,你所谓的“公认的规范写法”,就是 a |= (1<<5) 这样的吧 -_-

waitingconfirm 发表于 2011-6-29 23:47:15

回复【9楼】skyhu
回复【6楼】waitingconfirm
-----------------------------------------------------------------------
你真的很臭屁
-----------------------------------------------------------------------

臭屁送你,不必客气

1ongquan 发表于 2011-6-29 23:51:25

六楼

waitingconfirm 发表于 2011-6-29 23:54:41

回复【12楼】Cliff
回复【6楼】waitingconfirm
某些在软件上学不进新东西的“老一辈”电子工程师传出来的编程臭毛病罢了
也许某些编译器可以达到“老人”们yy的目的,但换个环境甚至只是换个编译器就基本上全砸
对于 c 语言来说,位操作是有其公认的规范写法的,耍这点小聪明,最后无非害人害己罢了
-----------------------------------------------------------------------
位操作?公认?小聪明?
那我问你:
union {
      struct {
         unsigned b0_3:4;
         unsigned b4_6:3;
         unsigned b7:1;
         }onebit;
      unsigned char allbits;
       } m......
-----------------------------------------------------------------------

C 语言中,位域并不是通用标准,也没有任何可以确保的实现方案,更重要的是,位域根本不定义大小端

因此,除非对编译器选项非常了解,能完全明白自己在做什么,否则很有可能得到完全驴唇不对马嘴的结果

相应的,移位和 ! & ~ 运算符在 C 语言中却有明确的标准规范,其实现的结果完全是确定而可预期的

当然,如果一个人完全了解自己所用的器件、完全了解自己所用的编译器、完全不考虑程序移植和换人接手的问题、也完全不介意把自己的技术生涯栓死在一个特定器件上,那么别说用位域了,就算用 switch 杂跳都没人介意

jackiezeng 发表于 2011-6-29 23:57:55

回复【15楼】waitingconfirm
回复【12楼】cliff   
回复【6楼】waitingconfirm
某些在软件上学不进新东西的“老一辈”电子工程师传出来的编程臭毛病罢了
也许某些编译器可以达到“老人”们yy的目的,但换个环境甚至只是换个编译器就基本上全砸
对于 c 语言来说,位操作是有其公认的规范写法的,耍这点小聪明,最后无非害人害己罢了
-----------------------------------------------------------------------
位操作?公认?小聪明?
那我问你:
union {
      struct {
         unsigned b0_3:4;
         unsigned b4_6:3;
         unsigned b7:1;
         }onebit;
      unsig......
-----------------------------------------------------------------------

不能理解位域和大小端有神马关系,,,共用体才需要注意大小端吧

tiancaigao7 发表于 2011-6-30 07:10:13

回复【6楼】waitingconfirm
-----------------------------------------------------------------------

楼主提供的这种写法可是很多大厂家(如microchip)提供的例程或者头文件的写法,别告诉我你认为这些大厂家里面的工程师都是你所谓的学不进新东西的老工程师。貌似咱们所谓的新东西都是人家吃完再吐出来的。不要说的太极端。

wuyya 发表于 2011-6-30 08:12:28

回复【17楼】tiancaigao7 天才杨威利
回复【6楼】waitingconfirm
-----------------------------------------------------------------------
楼主提供的这种写法可是很多大厂家(如microchip)提供的例程或者头文件的写法,别告诉我你认为这些大厂家里面的工程师都是你所谓的学不进新东西的老工程师。貌似咱们所谓的新东西都是人家吃完再吐出来的。不要说的太极端。
-----------------------------------------------------------------------

ST也是这样写的。

yealien 发表于 2011-6-30 08:55:37

我是看过共用体和结构体,但没看到过这种写法,unsigned b3:1;是什么意思呢?是oneBit里面的位3?:1又是什么呢?只用1个?
不过还是多谢大家的回覆!

ufbycd 发表于 2011-6-30 08:59:12

回复【6楼】waitingconfirm
某些在软件上学不进新东西的“老一辈”电子工程师传出来的编程臭毛病罢了
也许某些编译器可以达到“老人”们yy的目的,但换个环境甚至只是换个编译器就基本上全砸
对于 c 语言来说,位操作是有其公认的规范写法的,耍这点小聪明,最后无非害人害己罢了
-----------------------------------------------------------------------

你是说ANSI C 或C99里没有规定位域?!

请列出你所说的“公认的规范写法”。

ufbycd 发表于 2011-6-30 09:22:06

这样够不够狠:
// Structures
typedef union _REG
{
        BYTE Val;

        // EIE bits ----------
        struct {
                unsigned char RXERIE:1;
                unsigned char TXERIE:1;
                unsigned char :1;
                unsigned char TXIE:1;
                unsigned char LINKIE:1;
                unsigned char DMAIE:1;
                unsigned char PKTIE:1;
                unsigned char INTIE:1;
        } EIEbits;

        // EIR bits ----------
        struct {
                unsigned char RXERIF:1;
                unsigned char TXERIF:1;
                unsigned char :1;
                unsigned char TXIF:1;
                unsigned char LINKIF:1;
                unsigned char DMAIF:1;
                unsigned char PKTIF:1;
                unsigned char :1;
        } EIRbits;

        // ESTAT bits ---------
        struct {
                unsigned char CLKRDY:1;
                unsigned char TXABRT:1;
                unsigned char RXBUSY:1;
                unsigned char :1;
                unsigned char LATECOL:1;
                unsigned char :1;
                unsigned char BUFER:1;
                unsigned char INT:1;
        } ESTATbits;

        // ECON2 bits --------
        struct {
                unsigned char :3;
                unsigned char VRPS:1;
                unsigned char :1;
                unsigned char PWRSV:1;
                unsigned char PKTDEC:1;
                unsigned char AUTOINC:1;
        } ECON2bits;
               
        // ECON1 bits --------
        struct {
                unsigned char BSEL0:1;
                unsigned char BSEL1:1;
                unsigned char RXEN:1;
                unsigned char TXRTS:1;
                unsigned char CSUMEN:1;
                unsigned char DMAST:1;
                unsigned char RXRST:1;
                unsigned char TXRST:1;
        } ECON1bits;
               
        // ERXFCON bits ------
        struct {
                unsigned char BCEN:1;
                unsigned char MCEN:1;
                unsigned char HTEN:1;
                unsigned char MPEN:1;
                unsigned char PMEN:1;
                unsigned char CRCEN:1;
                unsigned char ANDOR:1;
                unsigned char UCEN:1;
        } ERXFCONbits;
               
        // MACON1 bits --------
        struct {
                unsigned char MARXEN:1;
                unsigned char PASSALL:1;
                unsigned char RXPAUS:1;
                unsigned char TXPAUS:1;
                unsigned char :4;
        } MACON1bits;
               

        // MACON3 bits --------
        struct {
                unsigned char FULDPX:1;
                unsigned char FRMLNEN:1;
                unsigned char HFRMEN:1;
                unsigned char PHDREN:1;
                unsigned char TXCRCEN:1;
                unsigned char PADCFG0:1;
                unsigned char PADCFG1:1;
                unsigned char PADCFG2:1;
        } MACON3bits;
        struct {
                unsigned char FULDPX:1;
                unsigned char FRMLNEN:1;
                unsigned char HFRMEN:1;
                unsigned char PHDREN:1;
                unsigned char TXCRCEN:1;
                unsigned char PADCFG:3;
        } MACON3bits2;
               
        // MACON4 bits --------
        struct {
                unsigned char :4;
                unsigned char NOBKOFF:1;
                unsigned char BPEN:1;
                unsigned char DEFER:1;
                unsigned char :1;
        } MACON4bits;
               
        // MICMD bits ---------
        struct {
                unsigned char MIIRD:1;
                unsigned char MIISCAN:1;
                unsigned char :6;
        } MICMDbits;

        // EBSTCON bits -----
        struct {
                unsigned char BISTST:1;
                unsigned char TME:1;
                unsigned char TMSEL0:1;
                unsigned char TMSEL1:1;
                unsigned char PSEL:1;
                unsigned char PSV0:1;
                unsigned char PSV1:1;
                unsigned char PSV2:1;
        } EBSTCONbits;
        struct {
                unsigned char BISTST:1;
                unsigned char TME:1;
                unsigned char TMSEL:2;
                unsigned char PSEL:1;
                unsigned char PSV:3;
        } EBSTCONbits2;
               
        // MISTAT bits --------
        struct {
                unsigned char BUSY:1;
                unsigned char SCAN:1;
                unsigned char NVALID:1;
                unsigned char :5;
        } MISTATbits;
               
        // ECOCON bits -------
        struct {
                unsigned char COCON0:1;
                unsigned char COCON1:1;
                unsigned char COCON2:1;
                unsigned char :5;
        } ECOCONbits;
        struct {
                unsigned char COCON:3;
                unsigned char :5;
        } ECOCONbits2;
               
        // EFLOCON bits -----
        struct {
                unsigned char FCEN0:1;
                unsigned char FCEN1:1;
                unsigned char FULDPXS:1;
                unsigned char :5;
        } EFLOCONbits;
        struct {
                unsigned char FCEN:2;
                unsigned char FULDPXS:1;
                unsigned char :5;
        } EFLOCONbits2;
} REG;

whhityang 发表于 2011-6-30 09:22:17

回复【19楼】yealien
我是看过共用体和结构体,但没看到过这种写法,unsigned b3:1;是什么意思呢?是onebit里面的位3?:1又是什么呢?只用1个?
不过还是多谢大家的回覆!
-----------------------------------------------------------------------

这个请看谭浩强的C语言“位域”一节。话说以前我也不认识,后来是好好的重看了几遍C语言书...

XA144F 发表于 2011-6-30 09:25:30

我用CCS给DSP写程序时就只有这个了,因为DSP的寄存器访问不能直接位寻址,只能用位域,其中每个位的信息和寄存器中的位是对应的,所以有大小端的要求。

比如DSP的SCI控制寄存器1:
structSCICTL1_BITS {       // bit    description
   Uint16 RXENA:1;         // 0      SCI receiver enable
   Uint16 TXENA:1;         // 1      SCI transmitter enable
   Uint16 SLEEP:1;         // 2      SCI sleep
   Uint16 TXWAKE:1;          // 3      Transmitter wakeup method
   Uint16 rsvd:1;            // 4      reserved
   Uint16 SWRESET:1;         // 5      Software reset   
   Uint16 RXERRINTENA:1;   // 6      Recieve interrupt enable
   Uint16 rsvd1:9;         // 15:7   reserved

};

http://cache.amobbs.com/bbs_upload782111/files_42/ourdev_653418WXXA3E.PNG
(原文件名:SCTCTL1.PNG)

bigZ 发表于 2011-6-30 11:02:36

使用 结构体+联合体 的混合体,在很多时候在程序操作上是极其方便的

也许如你所说,移位操作符合C规范,但是这会使得程序逻辑混乱,代码难于阅读和维护

有人说,程序的灵魂是数据结构,而不再是算法。

一个好的数据结构,决定了优秀的算法,一个烂数据结构,可能使算法变的很复杂

rqiang 发表于 2011-6-30 11:16:05

typedef unsigned char uchar;
typedef unsigned long ushort;

union        byte_type_t
{
        uchar byte;
        struct p8_bit
        {
           uchar bit0:1        ; // 1
           uchar bit1:1        ; // 2
           uchar bit2:1        ; // 3
           uchar bit3:1        ; // 4
           uchar bit4:1        ; // 5
           uchar bit5:1        ; // 6
           uchar bit6:1        ; // 7
           uchar bit7:1        ; // 8
        }bit;
};        

typedef volatile union byte_type_t BYTE;

union        word_type_t
{
        ushort word;
        struct p16_bit
        {
           uchar bit0:1        ; // 1
           uchar bit1:1        ; // 2
           uchar bit2:1        ; // 3
           uchar bit3:1        ; // 4
           uchar bit4:1        ; // 5
           uchar bit5:1        ; // 6
           uchar bit6:1        ; // 7
           uchar bit7:1        ; // 8
           uchar bit8:1        ; // 9
           uchar bit9:1        ; // 10
           uchar bit10:1        ; // 11
           uchar bit11:1        ; // 12
           uchar bit12:1        ; // 13
           uchar bit13:1        ; // 14
           uchar bit14:1        ; // 15
           uchar bit15:1        ; // 16   
        }bit;
};        

这样用也可以...

XA144F 发表于 2011-6-30 11:37:06

回复【25楼】rqiang
typedef unsigned char uchar;
typedef unsigned long ushort;
union        byte_type_t
{
        uchar byte;
        struct p8_bit
        {
           uchar bit0:1        ; // 1
           uchar bit1:1        ; // 2
           uchar bit2:1        ; // 3
           uchar bit3:1        ; // 4
           uchar bit4:1        ; // 5
           uchar bit5:1        ; // 6
           uchar bit6:1        ; // 7
           uchar bit7:1        ; // 8
        }bit;
};        
typedef volatile union byte_type_t byte;
union        word_type_t
{
        ushort word;
        ......
-----------------------------------------------------------------------

这时
word.bit13=1
等价于
word|=1<<13

eggcar 发表于 2011-6-30 11:55:33

6L说的对,不按标准来的后果就是出了问题你都看不出是什么问题来,这也是我非常讨厌很多人写的单片机程序的原因,也很讨厌很多非标编译器,当你看到一个在你所不了解的编译器上编译的一个你所不了解的器件的不按标准C写的程序的时候,你会完全不知所云。用C写就是要让人看懂的,反感把程序写的乱七八糟缩进参差不齐跟狗啃的似的变量名胡绉八扯表达式中间不加空格挤在一起还连英文带拼音恨不得连汉字都用上的人,我高中一哥们写的程序那叫一个狠,不小心瞟一眼都得折寿三年。注释这个东西我倒觉得看个人习惯,程序写清楚了不用注释也很容易看,函数定义处简单一标参数含义就行。

Cliff 发表于 2011-7-1 00:08:06

回复【27楼】eggcar 八号机
6l说的对,不按标准来的后果就是出了问题你都看不出是什么问题来,这也是我非常讨厌很多人写的单片机程序的原因,也很讨厌很多非标编译器,当你看到一个在你所不了解的编译器上编译的一个你所不了解的器件的不按标准c写的程序的时候,你会完全不知所云。用c写就是要让人看懂的,反感把程序写的乱七八糟缩进参差不齐跟狗啃的似的变量名胡绉八扯表达式中间不加空格挤在一起还连英文带拼音恨不得连汉字都用上的人,我高中一哥们写的程序那叫一个狠,不小心瞟一眼都得折寿三年。注释这个东西我倒觉得看个人习惯,程序写清楚了不用注释也很容易看,函数定义处简单一标参数含义就行。
-----------------------------------------------------------------------

1、什么是标准?什么是不按标准?位域是标准吗?
2、单片机程序,别妄想使用C的移植性。和硬件操作很多。如果你说“完全不知所云”,那你应该提高自己的水平,而不是限制研发人员。既然扩展了非标准C,那必然有它的用意。单片机资源紧缺,代码效率很重要。
3、注释,你要晓得,这是用来干什么的?是帮你理解程序思路的吗?不是的。它是帮助你使用程序的。也就是,函数的功能、参数、返回值,是需要的。而内部实现的说明,是可选(甚至不推荐使用)的。

eggcar 发表于 2011-7-1 00:35:32

回复【28楼】Cliff
-----------------------------------------------------------------------

我不知道单片机这个行业里有什么行规,但是在软件行业,你写程序是给别人看的,你花十分钟写的程序有可能几年后还有人在维护,给维护人员造成麻烦就是在浪费社会资源,浪费公司的效率。

这里不讨论可移植性,只要涉及到了硬件,即使PC机上的移植也是一个很复杂的问题。按照标准来的意思就是,1、你自己可以迅速适应不同平台的开发任务,避免各种标准间的混乱。2、维护人员并不一定熟悉你的开发环境,也不了解你的非标用法,很容易造成歧义,浪费大量时间。3、遵照ANSI C的标准完全可以实现的功能,为什么要去使用非标准语句造成大量的麻烦?
而且注释的功能不是给你自己看的,是给日后接你班的人看的,好的注释可以事半功倍,坏的注释则导致事倍功半。我不明白故意把程序写成火星文的人的思想是怎么样的,看到别人很痛苦你自己很爽??除非是有特殊需要,如一些网站的后台程序,曾经为了避免sql注入,我就用过把所有变量名做成字典,用乱码替换,给破_解者增加了无尽的难度。但是其他情况下绝对不推荐这么做,日后自己都很难维护。

如果器件商在库中使用特殊用法,可以理解,封装起来后不会对使用者造成不便,且器件商最了解其实现不会导致错误的结果。但是开发人员就要避免这些歧义性用法。
假如同样一句话在不同的平台下效果完全不同甚至相反,领会错意思难道是水平问题?ANSI里有许多未定义的依赖具体编译及硬件环境的地方,难不成就为了看个程序还得把相关资料翻个遍?没那闲工夫。还有优先级的问题,这都是讨论烂了的问题了,该括号就括号,别炫耀自己背过了优先级表。

Cliff 发表于 2011-7-1 01:26:23

回复【29楼】eggcar 八号机
-----------------------------------------------------------------------

> 你花十分钟写的程序有可能几年后还有人在维护,给维护人员造成麻烦就是在浪费社会资源,浪费公司的效率。
如果我写的程序,不是我来维护,而请别人维护,本身就是在浪费公司效率,浪费社会资源。

> 维护人员并不一定熟悉你的开发环境,也不了解你的非标用法
连开发环境都不熟悉,还维护什么?移植到另一个开发环境容易,还是熟悉原来的开发环境容易?

> 遵照ANSI C的标准完全可以实现的功能,为什么要去使用非标准语句造成大量的麻烦
既然是单片机领域,就不存在“遵照ANSI C的标准完全可以实现的功能”。这也是我上面说的,正因为有这方面需求才会有这样的编译器。

> 我不明白故意把程序写成火星文的人的思想是怎么样的
上面只是提到了位域,何来火星文?跑题了?

> 同样一句话在不同的平台下效果完全不同甚至相反,领会错意思难道是水平问题
如果说不同平台,那就是移植。移植出问题,当然是水平问题。

XA144F 发表于 2011-7-1 08:21:24

我记得“位域”国家二级C语言考试中出现过,怎么说是非标准的了?谭浩强的教材里面也是讲过这个的吧?

位域在给PC编程时的确没什么用。但是给DSP、ARM这样的嵌入式设备编程时用于寄存器控制是非常有效的,这时的标准C操作反而会容易混淆,造成代码阅读的困难。

另外,关于给嵌入式(或者说给单片机)的C编译器:编译器是多样的,不同的编译器为了不同的编译优化而增加了一些非标准的东西,比如AVR单片机的Code Vision AVR可以使用PORTB.4这样的方式去使用端口位,而别的单片机只能用标准位操作方式来实现,但是翻译为ASM之后都是SBI $18,4或者CBI $18,4,有什么问题呢?

“ 同样一句话在不同的平台下效果完全不同甚至相反,领会错意思难道是水平问题 ”
比如3+i++,不同的编译器的确会得到不同的结果,但是写出这样程序的是应该挨板子或者滚蛋的。

JSXA 发表于 2011-7-1 08:37:42

说实话 我这个位域也是刚刚知道 没多久
在我的映像里 好像没有哦 谭浩强的C 我是05年之前的书

g921002 发表于 2011-7-1 08:39:04

PC寫程式的思維跟寫嵌入式硬體的思維不一樣。把兩者的思維互相硬套在對方身上只是顯示自己的無知。

xbwpc 发表于 2011-7-1 09:01:28

点击此处打开 ourdev_653726LRUWE7.JPG(文件大小:3.89M,只有400K以内的图片才能直接显示) (原文件名:DSC01780.JPG)
点击此处打开 ourdev_653727D5GXY8.JPG(文件大小:3.81M,只有400K以内的图片才能直接显示) (原文件名:DSC01782.JPG)


这些书上的都是非标准?

XA144F 发表于 2011-7-1 09:20:50

回复【33楼】g921002
pc寫程式的思維跟寫嵌入式硬體的思維不一樣。把兩者的思維互相硬套在對方身上只是顯示自己的無知。
-----------------------------------------------------------------------

没错没错,在百度上看到一些人在说51单片机的keil中没有fopen函数,问如何打开文本文件。

典型的就是以前讨论的如何换算DS18B20的温度数据,在计算机上用乘以0.0625的方法没错,但是在单片机中还这么干的就真的没话说了。


回复【34楼】xbwpc
点击此处打开
点击此处打开
这些书上的都是非标准?
-----------------------------------------------------------------------
看着很像谭浩强的教材啊!

eggcar 发表于 2011-7-1 11:42:35

我无语,位域变成ANSI标准了?这算是谭浩强的又一个误导的功劳吗??少看谭浩强的书,多看看国外的教材吧
以下摘自KR的圣经The C Programming Language:

Almost everything about fields is implementation-dependent. Whether a field may overlap a word boundary is implementation-defined. Fields need not be names; unnamed fields (a colon and width only) are used for padding. The special width 0 may be used to force alignment at the next word boundary.

Fields are assigned left to right on some machines and right to left on others. This means that although fields are useful for maintaining internally-defined data structures, the question of which end comes first has to be carefully considered when picking apart externally-defined data; programs that depend on such things are not portable. Fields may be declared only as ints; for portability, specify signed or unsigned explicitly. They are not arrays and they do not have addresses, so the & operator cannot be applied on them.

C语言确实提供了位域操作,但却未定义位域的起始端,这根本就是一个plantform-based usage。你能够保证你对你所使用的编译器有足够深入的了解吗?你能够保证在不同平台间的频繁切换之下仍然对不同编译器的特性保持清醒的头脑吗?请你立刻说出你目前所使用的编译器中ANSI未定义的实现的具体实现,否则你这样使用就是在投机取巧碰运气。
不管是PC编程还是MCU的编程,符合标准以减少错误这一点是不变的。诚然,PC编程更注重开发效率而MCU的编程更注重运行效率,但是你的运行效率是基于正确运行的前提下的,况且我没看出来使用标准位操作比使用位域哪里降低执行效率了,以下摘自CSDN某博客:“尽管使用位域可以节省内存空间,但却增加了处理时间,在为当访问各个位域成员时需要把位域从它所在的字中分解出来或反过来把一值压缩存到位域所在的字位中. ”在熟悉这种表达方式后它阅读起来跟位域一样的清晰明了。而且搞MCU的人似乎从来都不考虑代码可维护性这一个给IT界带来了无数麻烦的讨论了几十年的问题。所以嘛,工资什么的都是有标准的,别太抱怨了。

XA144F 发表于 2011-7-1 12:25:53

要看位域是用在哪个地方的,虽然标准C提供了位域,但不是留着给PC用的。看前面的例子,那是控制MCU的功能寄存器使用的,在一个寄存器中有的功能用一个位实现,有的要用3个或者4个位来实现,所以使用位域方式去访问控制这些寄存器是非常好使的,这样看着直观,不易出错,如果用标准位操作,反而会让人看着头疼。

ufbycd 发表于 2011-7-1 12:45:00

回复【36楼】eggcar八号机
我无语,位域变成ansi标准了?这算是谭浩强的又一个误导的功劳吗??少看谭浩强的书,多看看国外的教材吧
以下摘自kr的圣经the c programming language:
almost everything about fields is implementation-dependent. whether a field may overlap a word boundary is implementation-defined. fields need not be names; unnamed fields (a colon and width only) are used for padding. the special width 0 may be used to force alignment at the next word boundary.

-----------------------------------------------------------------------

无非是个大小端所带来的可移植性的问题。

为一个MCU写程序还需要考虑这程序还能不能在其他的连大小端都不一样的MCU上能不能运行吗? 真是荒谬!!

你写每行程序都需要考虑大小端所带来的移植性吗? 嵌入式平台不是PC之类的通用平台!嵌入式的非通用性(特别是与IO相关的)正是她的本质所在!
有谁会不自己正在使用的MCU到底是大端还是小端?
有哪个项目是不需要修改就能同时在大小端平台上编译运行无误的?

搞MCU应该更专注于扩展性而非移植性。 另外,移植性和可维护性是两码事,扩展性才直接联系到可维护性。

caiyue3577 发表于 2011-7-1 12:48:49

回复【5楼】jackiezeng
位域 和 char 公用一个内存,,可以方便的操作一个位,也可以方便的得到所有位组成的这个字节的值,,
-----------------------------------------------------------------------

正解!

XA144F 发表于 2011-7-1 13:28:35

通用性只是方便了搞抄袭的人。

sunnyhook 发表于 2011-7-1 13:46:07

回复【40楼】XA144F
通用性只是方便了搞抄袭的人。
-----------------------------------------------------------------------

这里指的通用性是方便移植代码到不同的平台上,并不是为了方便抄袭。
这个问题对于不同能力的人来说,看法肯定不同,偏软件的人会认为这样的位操作不正规,偏硬件的人却认为很好用。

ufbycd 发表于 2011-7-1 13:57:47

回复【41楼】sunnyhook
回复【40楼】xa144f
通用性只是方便了搞抄袭的人。
-----------------------------------------------------------------------
这里指的通用性是方便移植代码到不同的平台上,并不是为了方便抄袭。
这个问题对于不同能力的人来说,看法肯定不同,偏软件的人会认为这样的位操作不正规,偏硬件的人却认为很好用。
-----------------------------------------------------------------------
你的说法没错。
除非项目明确规定,否则只有吃饱了没事干的人才会考虑连大小端都不一样的平台间的移植性。

在嵌入式里,是先有硬件才有软件,软件(即便是应用软件)是直接操作硬件的。平台不一样,硬件肯定不一样,理所当然的,相应的软件肯定也会不一样。
在嵌入式里过多地考虑可移植性只会耗费你更多的无谓的时间(最终可能是毫无意义的),使项目成本增高。

wwuchang 发表于 2011-7-1 15:26:53

mark,第一次看到这样的位操作,确实非常方便啊,我可不管是不是符合什么什么标准,好用就行了。

sunliezhi 发表于 2011-7-1 15:59:51

介意程序的通用性,可移植性,这没错; 不介意程序的通用性,可移植性,这也没错, 两者都没错,所谓:不可强求是也!
哈哈。

zy473551 发表于 2011-7-1 16:53:46

一直在用这种位操作!

eggcar 发表于 2011-7-1 17:58:32

回复【42楼】ufbycd
-----------------------------------------------------------------------

随便你们怎么想吧,我可没提过程序的可移植性,我说的是开发人员在不同平台下的适应性,你连我的话都没看全就别来反驳。当然国内某些技术人员一辈子磕死在一个平台下,那就无所谓了。
不跟你们讨论了,跟讨论是不是该用goto是一个性质的问题。标准就是用来遵守的,都不遵守要标准何用?爱咋写咋写,我没义务纠正。
Lang lebe streng Lang lebe Deutschland.Was fuer ein chaos nation China ist

marshallemon 发表于 2011-7-1 19:35:05

这是一种本身不带位操作的MCU操作位的办法

Cliff 发表于 2011-7-1 19:58:27

回复【46楼】eggcar 八号机
回复【42楼】ufbycd
-----------------------------------------------------------------------
随便你们怎么想吧,我可没提过程序的可移植性,我说的是开发人员在不同平台下的适应性,你连我的话都没看全就别来反驳。当然国内某些技术人员一辈子磕死在一个平台下,那就无所谓了。
不跟你们讨论了,跟讨论是不是该用goto是一个性质的问题。标准就是用来遵守的,都不遵守要标准何用?爱咋写咋写,我没义务纠正。
lang lebe streng lang lebe deutschland.was fuer ein chaos nation china ist
-----------------------------------------------------------------------

1、不用 goto 是什么标准?是 C 语言的标准?
2、一个设计一个平台,和一辈子一个平台,是一样的吗?
3、大家都认为你提的是任何程序要在各个平台下都有一致的行为。
4、请问你是做技术的么?
5、为什么要卖弄德文?你是中国人吗?你会用中文表达上面那话的意思吗?

kazenoai 发表于 2011-7-1 20:31:21

回复【30楼】Cliff
回复【29楼】eggcar 八号机
-----------------------------------------------------------------------
&gt; 你花十分钟写的程序有可能几年后还有人在维护,给维护人员造成麻烦就是在浪费社会资源,浪费公司的效率。
如果我写的程序,不是我来维护,而请别人维护,本身就是在浪费公司效率,浪费社会资源。
&gt; 维护人员并不一定熟悉你的开发环境,也不了解你的非标用法
连开发环境都不熟悉,还维护什么?移植到另一个开发环境容易,还是熟悉原来的开发环境容易?
&gt; 遵照ansi c的标准完全可以实现的功能,为什么要去使用非标准语句造成大量的麻烦
既然是单片机领域,就不存在“遵照ansi c的标准完全可以实现的功能”。这也是我上面说的,正因为有这方面需求才会有这样的编译器。
&gt; 我不明白故意把程序写成火星文的人的思想是......
-----------------------------------------------------------------------
我想说程序除了要实现功能以外,一个很重要的就是可维护性,你说的第一点我就很不同意,如果你离开了这家公司了呢?难道还叫你回来。。。

eggcar 发表于 2011-7-1 21:42:38

我从初中开始写程序有十年了,这些都是经验,能帮你少走弯路呢,那最好,不愿意听呢,我也管不着…就算只能帮到一个人我也算没白废口舌

waitingconfirm 发表于 2011-7-1 22:57:01

几天没注意这张帖子了……

其实我一直觉得,某些人如果用了 C 语言还在那里天天搞一堆家规则的玩意并以此为乐,你们干嘛不继续用回汇编去?你们既然不打算让别人接手维护你们的产品,那么请你们一开始就和公司商量好做成项目外包的合作形式,并且直接说明白了源代码不提交,不是更好?

成天做些损人不利己的事儿还以此为乐,很好玩么?

以上有感而发而已

waitingconfirm 发表于 2011-7-1 23:00:31

回复【50楼】eggcar八号机
禁止使用goto是作为职业程序员的标准,这个也要讨论吗?那我撤,这纯粹浪费时间了。

-----------------------------------------------------------------------

在非 C++ 环境下,Fatal Error 退出,不用 goto 几乎不可能的——这个在任何标准 C 库中都是在用的

goto 只是不能滥用,更不能随意用罢了,就跟临界区代码或共享资源防死锁访问一样,遵循严格的既定规范进行使用,就不会引入问题和误会

eggcar 发表于 2011-7-1 23:26:31

回复【53楼】waitingconfirm
回复【50楼】eggcar八号机
禁止使用goto是作为职业程序员的标准,这个也要讨论吗?那我撤,这纯粹浪费时间了。
-----------------------------------------------------------------------
在非 c++ 环境下,fatal error 退出,不用 goto 几乎不可能的——这个在任何标准 c 库中都是在用的
goto 只是不能滥用,更不能随意用罢了,就跟临界区代码或共享资源防死锁访问一样,遵循严格的既定规范进行使用,就不会引入问题和误会
-----------------------------------------------------------------------

这是c语言错误处理机制的鸡肋导致的。c里面可以用用setjmp()加上longjmp()处理异常,虽然也有一定崩溃危险性,不过比起goto来已经保证了程序结构的完整性了。至于一定要使用goto处理异常,暂时未遇到过。goto是程序可维护性最大的杀手。

cpp的异常处理就相当完善好用了,而且由于面向对象的封装性,goto更加不能使用了。

waitingconfirm 发表于 2011-7-1 23:29:29

再接着说位域

实际上,位域因为完全没有定义实现规则,因此,无论编译器用什么手段实现它,只要最终结果在逻辑意义上正确,就完全合理

比如说,楼主设定的位域方案,编译器完全可以根据优化需要随意的安排它们在内存中的位置,甚至可能做出将它们放置在不同字节这样的决定,而从定义逻辑上讲,这显然是正确的——并且也确实有一些编译器这样做过,至于大小端之类的,就更不用说了

waitingconfirm 发表于 2011-7-1 23:37:09

回复【54楼】eggcar八号机
回复【53楼】waitingconfirm
回复【50楼】eggcar八号机
禁止使用goto是作为职业程序员的标准,这个也要讨论吗?那我撤,这纯粹浪费时间了。
-----------------------------------------------------------------------
在非 c++ 环境下,fatal error 退出,不用 goto 几乎不可能的——这个在任何标准 c 库中都是在用的
goto 只是不能滥用,更不能随意用罢了,就跟临界区代码或共享资源防死锁访问一样,遵循严格的既定规范进行使用,就不会引入问题和误会
-----------------------------------------------------------------------
这是c语言错误处理机制的鸡肋导致的。c里面可以用用setjmp()加上longjmp......
-----------------------------------------------------------------------

setjmp 这套是库定义的虚函数或者宏,用做 fatal error 处置,引入的问题更多

个人来说,建议你有机会看看 BSD 类系统,特别是 OpenBSD 的内核源码,这些代码可以说是标准 C 语言编程在某种意义上的经典和巅峰之作,从这些代码里,应该能非常明白的看出什么地方可以用 goto

单从对 goto 的态度上讲,我个人觉得你也是受了奇怪的灌输的误导的结果——不要以为 C 语言中有 goto 是一个错误,真的……-_-

eggcar 发表于 2011-7-1 23:55:09

回复【56楼】waitingconfirm
-----------------------------------------------------------------------

不使用goto不是别人灌输的结果,是我自己得出来的经验。
确实不能说引入goto是一个错误,否则cpp也不会仅仅为了一句向前兼容性就把goto又带进去了。更何况是最接近底层的c。

但是如果一开始就允许初学者使用goto语言的话,那么他永远都学不会结构化程序。就是因为goto太方便太强大编译后就是一个jmp,它把汇编的思想带进了结构化语言,一旦迷恋上使用goto就很难再放弃它。我是从basic开始接触编程的,那个时候就喜欢goto跳来跳去,但是越到后来接触到复杂的程序,越发的感觉到goto对程序结构的破坏性,越发的感觉到一处使用goto的方便会导致整个程序结构的混乱以至于整个流程更加复杂甚至是引入意料之外的路径,要处理好goto要耗费太多精力了。所以一直到现在,我坚决反对在程序中使用goto。

bsd的内核这个我真没看过,这个没有发言权,有机会会去拜读的,这样的经典一定会让我对编程思想有更深入的理解的,感谢推荐。

chenchuan 发表于 2011-7-2 09:00:17

工程上的东西,不同的人有不同的习惯,
有些东西是争论不出结果的,
不要把自己的习惯强加给别人,
有些人一看到和自己不同的观点就上纲上线,开始骂人,开始BS
说实话,这些人我是有点BS的,虽然我也犯了相同的错误。。。。。

比如goto,我从来没用过goto,但是我并不觉得应该绝对禁止goto
有人说不用goto可以写出任何程序,这个我相信
可是,while,for,continue,break这些东西哪一个是非要不可的?
没有它们我也可以写出任何程序,但是我并不觉得需要禁止使用这些东西

再说回标准化的东西
希望写个标准的c程序在任何平台上都能使用的人估计没怎么做过实际的工作
标准的c程序除了写个hello world很难写出别的东西
你想在屏幕上画个圈?平台相关
你想tcpip?平台相关
你想检查下一个目录下有什么文件?平台相关
事实上一个字节有8位?平台相关
涉及到输出输入,十有八九是平台相关的
这个论坛上应该是硬件工程师比较多吧,mcu的开发环境更加是平台相关很厉害的东西
keil51这样的程序waitingconfirm和八号机估计是从来不写的吧,
因为换个编译器肯定完蛋,完全不符合两位的审美观
嗯,也许51这样又老又土的东西两位确实看不上

强烈要求两位把你们平时写的比较大的程序贴点精华上来让大家摹拜下

eggcar 发表于 2011-7-2 10:33:12

回复【58楼】chenchuan
-----------------------------------------------------------------------

你还是没看帖,我从来从来都没有说过,标准化编程是为了平台间的可移植性。

不同的平台有不同的处理结构存储结构,不同的寄存器不同的外设不同的指令集,怎么可能不做任何改变就移植?这样理解我说的话的人自己做过移植吗?我有说过不应该使用库吗?错,我恰恰支持使用器件商提供的库封装。使用库简化了代码的编写和维护过程,又不会产生歧义,何乐而不为?但是按照你们的理论,用了库还怎么移植??

标准化编程是为了人看到程序就能正确得出结果,不光是你自己,还有将来接你班的维护人员。a = b + c++ + ++d;这种语句你能告诉我它的含义吗?我想任何人都不会允许自己的程序中出现这样的语句。但是为什么跟这个语句完完全全有相同问题的位域就这么多人支持呢?而标准位操作只要做一些封装工作,跟位域用起来一样方便,为什么非要用一个没有任何好处只有坏处的用法来代替一种严谨的高效的语法呢?让一个自己看不到内部的黑盒子编译器决定自己程序的命运?funny~

你如果一辈子死磕在keil下面,你可以无视我说的话。

关于禁止使用goto也不是我一个人说了算的,这是一个古老的问题了,想再纠结这个问题就去csdn吧,那边闲人很多的。

我不想再废话了,我要表达的思想我都说了,事实上这些问题都是说了几十年的老调了,而且根本没人认真看帖,再费口舌没有任何意义,算我手贱,打了这么多字。

ufbycd 发表于 2011-7-2 12:49:32

回复【59楼】eggcar八号机
回复【58楼】chenchuan
-----------------------------------------------------------------------
你还是没看帖,我从来从来都没有说过,标准化编程是为了平台间的可移植性。
不同的平台有不同的处理结构存储结构,不同的寄存器不同的外设不同的指令集,怎么可能不做任何改变就移植?这样理解我说的话的人自己做过移植吗?我有说过不应该使用库吗?错,我恰恰支持使用器件商提供的库封装。使用库简化了代码的编写和维护过程,又不会产生歧义,何乐而不为?但是按照你们的理论,用了库还怎么移植??
标准化编程是为了人看到程序就能正确得出结果,不光是你自己,还有将来接你班的维护人员。a = b + c++ + ++d;这种语句你能告诉我它的含义吗?我想任何人都不会允许自己的程序中出现这样的语句。但是为什么跟这个语句完完全全有相同问题的位域就这......
-----------------------------------------------------------------------

位域 跟 “a = b + c++ + ++d;”是不大一样的。

不同的编译器实现位域的方式是不一样,但结果都是一样的,除非编译器有问题。
就像不同的编译器对同一语句的编译或优化方式是不一样的,或者编译出来的汇编代码是不一样的,但结果都是一样的,只要保证这点就不会有任何问题,也不会产生任何歧义。歧义,是相对于结果而言的,只要保证结果一样,就不会有歧义。

而“a = b + c++ + ++d;”实现方式不一样结果就不一样,这是两者的本质区别。

bsz84 发表于 2011-7-2 14:22:01

大家放弃争论,一起讨论。

chenchuan 发表于 2011-7-2 21:25:51

仔细看了八号机说过的话,嗯,确实没说过移植到不同平台的事情,这个是我的错
我们还是就事论事吧,我也写过这么多年代码了,一直也觉得自己算是个好的程序员,
我还真不知道位操作有哪种标准写法,除此写法之外的写法都是错误的?

按我的理解,你强调的是程序的可读性,你觉得LZ列出来的那种写法可读性不好,
那你给我们来一段可读性好的,无歧义的代码吧

ufbycd 发表于 2011-7-2 23:04:24

回复【62楼】chenchuan
-----------------------------------------------------------------------

同求

光说无用,都是纸上谈兵,给出比对才能让人心悦诚服。

CHENXIAOTIAN 发表于 2011-7-2 23:38:06

MARK围观……

eggcar 发表于 2011-7-3 13:03:00

回复【62楼】chenchuan
-----------------------------------------------------------------------

回复【63楼】ufbycd
-----------------------------------------------------------------------

#define set_myFlag(x) (myFlag|=(1<<x))
#define reset_myFlag(x) (myFlag&=~(1<<x))
#define read_myFlag(x) ((myFlag>>x)&1)
#define invs_myFlag(x) (myFlag^=1<<x)

这是很基本的位操作封装,任何程序员都应该会用,或者把myFlag也作为一个参数写也行。
我认为用起来很方便,不比位域写法难懂,而且可以保证在任何符合ANSI标准的c compiler下编译得到相同的结果。

ufbycd 发表于 2011-7-3 15:31:51

回复【65楼】eggcar八号机
回复【62楼】chenchuan
-----------------------------------------------------------------------
回复【63楼】ufbycd
-----------------------------------------------------------------------
#define set_myflag(x) (myflag|=(1<<x))
#define reset_myflag(x) (myflag&=~(1<<x))
#define read_myflag(x) ((myflag>>x)&1)
#define invs_myflag(x) (myflag^=1<<x)
这是很基本的位操作封装,任何程序员都应该会用,或者把myflag也......
-----------------------------------------------------------------------

可读性根本没法跟位域比!

如果把 “myFlag”也作为参数就变成了这样:
#define set(flag, x) (flag |= (1 << x))
那就需要牢牢记住x是哪个flag中的,因为具体的flag和和具体的x可以随意组合,而位域则不会,如果位域不在这个flag中会通不过编译。
你敢保证你能你时刻保持清醒记住所有的位是在第几位、并且是在哪个flag中的吗?
如果这些变量比较多,你说哪个更容易出错?等到出错了,你也能很容易地找到错误吗?这几乎就是大海捞针!

而如果不将“flag”做成参数,是不是会有一大堆这种宏定义?这样维护起来就很轻松吗?

位域将位和其所属的变量绑定起来,不留给你记错的余地!

eggcar 发表于 2011-7-3 16:41:21

那么你只需要将传递的x使用一个enum类型或者再多做几个define把位的位置用其含义名称代替,传递位的名称而不是数字,这样也会容易犯错吗?代码量并不比位域大,含义也更清晰…更进一步就把flag和位的名称位置封装成struct,更不会出错了。

Cliff 发表于 2011-7-3 22:04:46

回复【51楼】eggcar 八号机
我从初中开始写程序有十年了,这些都是经验,能帮你少走弯路呢,那最好,不愿意听呢,我也管不着…就算只能帮到一个人我也算没白废口舌
-----------------------------------------------------------------------

首先,这边是嵌入式,而不是软件的论坛。就像后面有人举的OpenBSD的例子。你用软件工程那套,生搬硬套到嵌入式,特别是深度嵌入式系统内,是非常不恰当的。我举个例子:你通用平台的软件设计,会使用内嵌汇编吗?

然后,如果你初中开始编程,到现在才10年的话,年纪还不大。所以也别认为10年的编程经验就很强。也别以为自己的一定是正路,不听你的一定会走弯路。我们这一代,最缺乏的就是质疑的精神,被“家长化苦口婆心的管理”、“应试”伤的太多。就算你有多强的经验,也应该让初学者们懂得探索。

chenchuan 发表于 2011-7-3 22:07:58

嗯,八号机的写法确实有可取之处,我个人意见如果有人觉得这种写法比较好,不妨用用
不过要说这种写法就完全替代位域,位域就是应该废止的垃圾我看也不未必

考虑这样的情况
union.bits.b1=union.bits.b5
八号机的方法就变成了
if(get_bits(5))set_bit(1);
else reset_bit(1);
代码长了很多

再比如12楼举的例子
类似情况比如约定有4位代表月份,定义month:4
现在要对此月份赋值,要运算,用位域就很清楚明白
union.bits.month=5
union.bits.month=union.bits.month+1
八号机的方法这样的宏定义就会比较复杂
而且如果修改了位域的长度,用位域只需要修改一处
八号机有可能需要重写所有的宏定义,还要自己数好第几位到第几位是哪个域

位域最主要的问题就是分配的时候不知道是从高开始还是从低开始
我们大多数时候写程序都是固定平台运行,所以这个问题并不一定很严重

一种写法是否直观这是“主观问题”
八号机平时用宏定义来处理位操作
所以就看位域方法不直观,不标准,感觉看不明白
两样,别的人平时一直用位域方法处理位操作
当然看起来感觉很直观,很标准,看起来很明白

再次重复我的观点:
八号机的写法确实有可取之处,不过并不是废除位域的理由

chenchuan 发表于 2011-7-3 22:16:16

八号机小弟弟,看了你的帖子感觉你真的挺不错
技术上有一套,为人也不错,自己有心得,千方百计想帮助别人
所以这里我想说,我们的分歧是技术看法,讨论问题也对事不对人
无论如何讨论,千万别人身攻击,别伤了和气

ufbycd 发表于 2011-7-4 09:16:27

我所强调的是与或非的写法不能把位和其对应的变量对应起来。如果MCU的IO库如Microchip的,都写成这种形式式,那么使用者就可能不但需要记住几十个寄存器变量更要记住上百个甚至几百个位。而一但出错,也就无从下手,只好一条语句一语句地去检查位与变量的对应关系是否正确。
    这让我想起一个项目:这个项目所使用的MCU是台系一家小厂,他的MCU的开发不支持C语言并且连汇编编译器都做得很烂。他的设置寄存器位的指令是这样的:SET reg, bit   其中reg是寄存器、bit是其位,两者是分开的,是同一指令的两个操作数。当然这两者都做成了汇编宏,不需要记住他们的地址和位址是多少。然而两者实际上都是一样数字,并且没有什么关联,有时甚至都分不清这到底是寄存器地址还是位地址,最害怕的就是将原本属于reg1的bit1使用到reg2上了,写出这样的东西:SET reg2,bit1,如果记得不是很清楚,谁能一眼就能看出这个错误。于是开发的时候就很害怕很小心,有时甚至根本不相信自己所记得的是对的,只好每写句就看手册一眼,即便是这样还是觉得很容易出错很不安,所以非常苦恼。这就严重地影响了开发速度。
    如果Microchip或ST的IO库写成这样,恐怕大部分的人都要骂库很垃圾。

dikex 发表于 2011-7-4 10:57:30

union {
      struct {
         unsigned b0:1;
         unsigned b1:1;
         unsigned b2:1;
         unsigned b3:1;
         unsigned b4:1;
         unsigned b5:1;
         unsigned b6:1;
         unsigned b7:1;
         }oneBit;
      unsigned char allBits;
       } myFlag;

对于上面这个例子,各个位的高低分配在对某个位读写时根本一点影响都没有;先使用myFlag.oneBits.b4=1赋值,再使用a=myFlag.oneBits.b4取值,无论是b7...b0,或者b0...b7,得出的结果都是对的;
而高低位分配的影响是对于union里面的allBits,只用当使用myFlag.allBits进行多个位的读写时才会出问题(全清0或置1除外),
把外面那层union去掉或者不用myFlag.allBits进行全清0或置1外的多位读写,无论在哪种编译器里面使用都不会有问题;

所以问题所在并不是位域,而是位域与union的搭配,但即使不是位域,在使用union都是需要注意字节存储顺序(ENDIANNESS),在不同环境下16位数据0x1234的存储方式可能是12 34或者34 12,如果再设计到数据类型的长度问题,那需要注意到问题就更多了

另外大部分的MCU都有专门的位操作指令,因为MCU上面的位操作非常频繁,因此移位+与或等操作和直接操作位,两种方式在执行效率上是有很大区别的,而MCU所在地场合基本上都是非常注重执行效率的,如果不是汇编的开发效率相对不够高而且C编译器的改进,相信很大部分人在MCU上还是会选择汇编,况且现在还有很多用汇编的

athena_min 发表于 2011-7-4 11:33:48

学习了

waitingconfirm 发表于 2011-7-5 13:07:05

回复【58楼】chenchuan
这个论坛上应该是硬件工程师比较多吧,mcu的开发环境更加是平台相关很厉害的东西
keil51这样的程序waitingconfirm和八号机估计是从来不写的吧,
因为换个编译器肯定完蛋,完全不符合两位的审美观
嗯,也许51这样又老又土的东西两位确实看不上
-----------------------------------------------------------------------

简单的说吧,我用 51 的时候,中国还没人听说过 Internet

我用 Keil 的时候,这个论坛还不知道在哪里

而正是因为用 Keil 写出了大量根本无法移植的程序,所以才在很多年前就明白了一个道理:

如果一个编译器写出来的东西是专门不能让人顺利移植的,那么用这个编译器不如直接用汇编

waitingconfirm 发表于 2011-7-5 13:16:56

或者用一个更简单的说法:

标准的 51 器件中,位操作一次只能针对特定一个位进行操作,换句话说,如果设定 C 语言位域结构体,则 1 位的位域和超过 1 位的位域,实际实现的二进制代码就是完全不同的,而且我可以肯定的说,对于超过 1 位的位域处理,任何 51 编译器都不可能处理的比移位->掩码的效果更好,而且在很多特殊情况下,程序员可能会有更明确简洁的处理措施,而这,都是编译器无从也无可能了解的,更遑论 51 器件只能对极少部分 RAM 区进行位操作,这就更进一步增加了程序的不确定性

总体而言,位域在任何意义上都会导致代码的一致性下降,而这往往也就意味着代码的实时性下降——当不同位数的位域实现其使用的机器周期肯定不同时,我完全看不出这东西到底会有什么正面意义在……

chenchuan 发表于 2011-7-5 16:47:57

回复【74楼】waitingconfirm
回复【58楼】chenchuan   
这个论坛上应该是硬件工程师比较多吧,mcu的开发环境更加是平台相关很厉害的东西
keil51这样的程序waitingconfirm和八号机估计是从来不写的吧,
因为换个编译器肯定完蛋,完全不符合两位的审美观
嗯,也许51这样又老又土的东西两位确实看不上
-----------------------------------------------------------------------
简单的说吧,我用 51 的时候,中国还没人听说过 internet
我用 keil 的时候,这个论坛还不知道在哪里
而正是因为用 keil 写出了大量根本无法移植的程序,所以才在很多年前就明白了一个道理:
如果一个编译器写出来的东西是专门不能让人顺利移植的,那么用这个编译器不如直接用汇编

-----------------------------------------------------------------------
keil c的程序确实不容易移植,不过应该还是比汇编的代码容易移植吧
keil的设计者我想也不会专门设计让人不能顺利移植,而只是技术上做不到可以方便移植吧

另外51的程序你准备移植到哪?移植到不同的cpu?
就通常情况,方便移植的代码多半要带来效率、功能、代码长度等资源的损失
如果一种写法没有任何副作用的比另一种写法要强,那它肯定已经把后一种写法淘汰了
既然还没有淘汰,那多半是有你还没有考虑到的因素而不是别人都是笨蛋
八号机拿出了自己的代码,用事实来说话
尽管他还没有证明位域一无是处
waitingconfirm 你都没有写出自己的代码就在说位域的不好
未免有些太武断了吧

Cliff 发表于 2011-7-5 19:55:03

回复【74楼】waitingconfirm
而正是因为用 keil 写出了大量根本无法移植的程序,所以才在很多年前就明白了一个道理:
如果一个编译器写出来的东西是专门不能让人顺利移植的,那么用这个编译器不如直接用汇编
-----------------------------------------------------------------------

1、Keil C51,至少更方便在同平台不同MCU之间的移植;而汇编不具备这个特性。
2、万事古难全,在51当道的日子,这样一款非冯诺依曼架构的MCU,要使C具备ASM的效率,非标准是必须的。
3、有些事情要怪自己,不要都算到编译器头上。
4、任何一个编译器写出来的东西,都无法顺利移植到另一个完全不同的平台:比如从Windows移植到Linux。系统,是远大于编译器的,你眼睛里要有系统,而不是编译器。
5、确实C51有些致命缺陷,比如它的指针。

tootzoe 发表于 2011-7-5 20:37:02

位域这种写法有 "面向对象"风格, 我喜欢,经常用,用 宏 是很头大的
goto我经常用来获得 "清理现场代(错误处理)码只写一次" 这种效果

esdart 发表于 2011-7-5 20:55:21

回复【30楼】Cliff
回复【29楼】eggcar 八号机
-----------------------------------------------------------------------
&gt; 你花十分钟写的程序有可能几年后还有人在维护,给维护人员造成麻烦就是在浪费社会资源,浪费公司的效率。
如果我写的程序,不是我来维护,而请别人维护,本身就是在浪费公司效率,浪费社会资源。
&gt; 维护人员并不一定熟悉你的开发环境,也不了解你的非标用法
连开发环境都不熟悉,还维护什么?移植到另一个开发环境容易,还是熟悉原来的开发环境容易?
&gt; 遵照ansi c的标准完全可以实现的功能,为什么要去使用非标准语句造成大量的麻烦
既然是单片机领域,就不存在“遵照ansi c的标准完全可以实现的功能”。这也是我上面说的,正因为有这方面需求才会有这样的编译器。
&gt; 我不明白故意把程序写成火......
-----------------------------------------------------------------------

员工离职再正常不过,如果你离职了,原公司还会让你维护吗?就算让你维护,你会去做吗?

johnwjl 发表于 2011-7-5 21:02:25

任何事情都是矛盾体,都具有两面性,goto一样,位域处理方法也一样。

Cliff 发表于 2011-7-5 21:24:57

回复【81楼】esdart 依斯达特
回复【30楼】cliff
> 你花十分钟写的程序有可能几年后还有人在维护,给维护人员造成麻烦就是在浪费社会资源,浪费公司的效率。
如果我写的程序,不是我来维护,而请别人维护,本身就是在浪费公司效率,浪费社会资源。
-----------------------------------------------------------------------
员工离职再正常不过,如果你离职了,原公司还会让你维护吗?就算让你维护,你会去做吗?
-----------------------------------------------------------------------

1、离职真的是正常不过的事情吗?在我看,不是的。人要有积累,才能有所作为。之所以频频离职,肯定有原因的。
2、与其花大代价做好让位置的人来维护,不如用更人性化的管理留住开发人员。很多事情都是大家退一步海阔天空。

zbazba 发表于 2011-7-5 21:44:58

还是菜鸟的 飘过
       ___
      (">
       )(
      // )
   --//""--
   -/------

stepme 发表于 2011-7-5 23:29:51

看到一帮高人。。。。

g921002 发表于 2011-7-5 23:57:46

這種東西也能吵這樣久?....

walter_wang 发表于 2011-7-6 00:17:39

看了这个帖子的争论,我有时光回退15年的感觉。

OTD_WIND 发表于 2011-7-6 01:39:59

看完后,觉得位域方便是方便了,但好像效率低了。(当然这是我猜的~ 没用过所以不知道编译的的汇编是怎样的。)

我来MARK的,只是顺便发发感慨,别拍我哦
PS:这几年来几乎没接触程序;对软件了解最深的只有汇编,所以对程序只重效率与可读性。

diannaoza 发表于 2011-7-6 03:07:15

unsigned b0:1;
         unsigned b1:1;
         unsigned b2:1;
         unsigned b3:1;
         unsigned b4:1;
         unsigned b5:1;
         unsigned b6:1;
         unsigned b7:1;

在结构体内比如:unsigned b3:1;是什么意思呢?不是赋值吧?
===========================================================

转载文本1.


位段以位为单位定义结构体(或共用体)中成员所占存储空间的长度。含有位段的结构体类型称为位段结构。 位段成员必须被声明为unsigned或int类型。

位段结构也是一种结构体类型,只不过其中含有以位为单位定义存储长度的整数类型位段成员。采用位段结构既节省存储空间,又可方便操作。

位段结构中位段的定义格式为:

   unsigned <成员名>:<二进制位数>

例如:

struct bytedata

{unsigned a:2;   /*位段a,占2位*/

unsigned:6;/*无名位段,占6位,但不能访问*/

unsigned:0;   /*无名位段,占0位,表下一位段从下一字边界开始*/

unsigned b:10;/*位段b,占10位*/

int i;          /*成员i,从下一字边界开始*/

}data;

位段数据的引用:

同结构体成员中的数据引用一样,但应注意位段的最大取值范围不要超出二进制位数定的范围,否则超出部分会丢弃。

例如:data.a=2;   但data.a=10;就超出范围(a占2位,最大3)



关于位段数据,注意以下几点:



(1)一个位段必须存储在同一存储单元(即字)之中,不能跨两个单元。如果其单元空间不够,则剩余空间不用,从下一个单元起存放该位段。

(2)可以通过定义长度为0的位段的方式使下一位段从下一存储单元开始。

(3)可以定义无名位段。

(4)位段的长度不能大于存储单元的长度。也不能定义位段数组。

(5)位段无地址,不能对位段进行取地址运算。

(6)位段可以以%d,%o,%x格式输出。

(7)位段若出现在表达式中,将被系统自动转换成整数。

将struct和union类型结合使用,即发挥了指针运算的高效,又保护了原始数据不被破坏。具体实现方法如下:

typedef union    /*8位位段分解类型*/

{char value;

struct

{unsigned b0:1;

unsigned b1:1;

unsigned b2:1;

unsigned b3:1;

unsigned b4:1;

unsigned b5:1;

unsigned b6:1;

unsigned b7:1;

}bits;

}

bits8;

这样,用该结构来保存数据,即可以用.value来保存和访问数据,又可以用.b0、.b1...来访问第1、2...等位,非常方便。


转载文本2.(本坛)
不用位操作就是最好的位操作。而且放到哪里都可以用,
在不用位段的情况下改变一个字节的其中某几位

#define elegant 7
#define beauty 6

unsigned char value = 0;
/** 置位第7位 */
value |= (1<<elegant);
/** 清零第6位 */
value &= ~(1<<beauty);

这样的位操作才是,优雅的,方便移植的,并且很多工程师都嫌麻烦的。


C语言为位操作提供了位段这种方式,也是为大家熟悉的。
下面是用位段的方式


第二种方式

/** 声明位段结构类型 */
typedef struct {
    volatile unsigned _0 :1;
    volatile unsigned _1 :1;
    volatile unsigned _2 :1;
    volatile unsigned _3 :1;
    volatile unsigned _4 :1;
    volatile unsigned _5 :1;
    volatile unsigned _6 :1;
    volatile unsigned _7 :1;
}bit_field;

bit_field value ;

/** 置位第7位 */
value._7 = 1;
/** 清零第6位 */
value._6 = 0;

这是那些无法割舍位操作的工程师所常用的,并以此为乐。

这种方式,有个缺点,因为它必须声明成结构体,就无法整体赋值了,例如 value = 0×55 ; 是无法通过编译的,那么怎样才能既能使用位操作,又能整体赋值呢?可用下面这种方式:

第三种方式

typedef struct {
    volatile unsigned _0 :1;
    volatile unsigned _1 :1;
    volatile unsigned _2 :1;
    volatile unsigned _3 :1;
    volatile unsigned _4 :1;
    volatile unsigned _5 :1;
    volatile unsigned _6 :1;
    volatile unsigned _7 :1;
}bit_field;

/** 定义位操作宏*/
#define BitAccess(addr) (*((volatilebit_field *) (addr)))
#define vbit (*((volatilebit_field *) (&value)))

/** 普通方式声明变量 */
unsigned char value = 0;

/** 定义变量位*/
#define vbit3         BitAccess(&value)._3

/** 整体赋值,OK*/
value = 0x55;
/** 单独某位赋值1,OK*/
vbit3 = 1;
/** 单独某位赋值2,OK*/
vbit._2 =1

由于都是C语言的标准用法,所以无关平台,只要编译支持标准C,都可以这样使用。可以使用第三种方式来让某些不支持位操作的单片机”支持”位操作,例如


#define PA1BitAccess(&PORTA)._1

/** PA1口输出1 */
PA1 = 1;

第三种方法似乎很好玩,但是要小心使用,特别是这些位变量参与运算时,要格外小心。例如以下代码,vbit3 为上面声明的位变量

RC3 = vbit3;

假设RC3是某个系统定义的位地址,那么就要小心等号两边的数据类型,靠谱的编译器会给出警告,有些则不会。
再看这个取反操作,vbit3 为上面声明的位变量:

vbit3 = !vbit3;

大家知道取反是一个字操作,操作前会把不足16位的变量不足16位,至于结果如何,只有编译器清楚。一般为了安全,我会再套一层宏:

#define val(x)(((x)==1)?1u:0u)
#define inv(x)(((x)==1)?0u:1u)

RC3 = val(vbit3);
vbit3 = inv(vbit3);

关于第三种方法,在某些平台或者某些编译器上,会产生比较多的汇编代码,请注意!




本贴被 forestchen 编辑过,最后修改时间:2010-12-30,11:08:08.

Cliff 发表于 2011-7-6 08:54:24

回复【89楼】diannaoza 龙天
-----------------------------------------------------------------------

你就别贴这种人云亦云、误导初学者的东西了,正是你这种帖子思维方式的存在,才会让这个帖子争论不休

mydows 发表于 2011-7-6 09:10:05

受教了!

ufbycd 发表于 2011-7-6 10:05:23

不谈自己的工程实践体会,那就都是在纸上谈兵,鸟都不用鸟!

waitingconfirm 发表于 2011-7-6 10:14:29

回复【77楼】chenchuan
keil c的程序确实不容易移植,不过应该还是比汇编的代码容易移植吧
keil的设计者我想也不会专门设计让人不能顺利移植,而只是技术上做不到可以方便移植吧

另外51的程序你准备移植到哪?移植到不同的cpu?
就通常情况,方便移植的代码多半要带来效率、功能、代码长度等资源的损失
如果一种写法没有任何副作用的比另一种写法要强,那它肯定已经把后一种写法淘汰了
既然还没有淘汰,那多半是有你还没有考虑到的因素而不是别人都是笨蛋
八号机拿出了自己的代码,用事实来说话
尽管他还没有证明位域一无是处
waitingconfirm 你都没有写出自己的代码就在说位域的不好
未免有些太武断了吧
-----------------------------------------------------------------------

在我看来,keil C 本来就是披着 C 语言皮的“其它”语言,它与 C 语言之间的距离大致等同于 PHP 和 C 语言之间的距离……还要略大于 Java 和 C++ 之间的距离……

至于说移植……简单说吧,这两年虽然 AVR 由于种种原因很不灵光了,可有一阵子真的非常风光的,价格便宜性能超好,那时候很多产品为了能在不增加成本的前提下增加功能,都在二代产品中用 AVR 替换 51 来着,外围电路基本一致,外围硬件逻辑完全一致——这时候正常人的第一个想法难道不是移植?那除非你一开始就知道自己原本的程序写得很烂才会不考虑移植吧?

至于说笨蛋什么的,我倒真没有把别人当笨蛋的意思,但我知道很多人确实是懒蛋,而且还是那种比较没素养的懒蛋(有素养的懒蛋,就是那类为了懒得洗衣服发明洗衣机、为了懒得割麦子发明收割机的人),一旦首先被灌输了一种做法,往往在它确实搞出麻烦之前都不会去考虑它到底有没有潜在的问题

当然这也无所谓,人各有所好么……

不过,明明是潜藏风险的做法,还要拿来当宝,硬要教其他人也这么用,这就不是光懒的问题了吧?

继续谈回技术:

我早 N 年就不用 Windows 了,所以 keil 跟我那是基本没关系了,现在我偶尔的偶尔改改 51 的代码,都是用 sdcc 的,性能好不好还在其次,至少它规矩,程序写出来通用性高

如果您觉得我之前的话只是在无根据的胡扯,不妨这样好了:

您拿 keil(或随便您选中的哪款您喜欢的编译器)写段测试代码,分别做 3 位、2 位、1 位位域的运算操作,记下编译器生成的汇编码,然后再用移位掩码做同样的三次操作,用同一个编译器编译,对比一下两种代码在汇编码上的区别,如何?

Cliff 发表于 2011-7-6 10:38:32

回复【93楼】waitingconfirm
-----------------------------------------------------------------------

感觉你说话不着边际啊

〉在我看来,keil C 本来就是披着 C 语言皮的“其它”语言,它与 C 语言之间的距离大致等同于 PHP 和 C 语言之间的距离……还要略大于 Java 和 C++ 之间的距离……

PHP和C是什么距离,JAVA和C++又是什么距离?
PHP是脚本语言;C是编译语言。
JAVA靠虚拟机,有内存回收机制;而C++看了之后,还是能明白对应的机器代码的。
你说C51的差别大于等于这两个,你说出他们的区别了吗?

〉这时候正常人的第一个想法难道不是移植
当然不是!除非是走量的产品,且价格有优势,这时正常人才会考虑移植。
可你上面提到的却是性能、升级。这和移植是不一样的。

〉对比一下两种代码在汇编码上的区别
在拿出区别前,我先问问你,你期望的区别,是怎么样的?然后再按你要求生成代码,看是不是如你所说?

waitingconfirm 发表于 2011-7-6 11:05:52

回复【94楼】Cliff
感觉你说话不着边际啊
〉在我看来,keil c 本来就是披着 c 语言皮的“其它”语言,它与 c 语言之间的距离大致等同于 php 和 c 语言之间的距离……还要略大于 java 和 c++ 之间的距离……
php和c是什么距离,java和c++又是什么距离?
php是脚本语言;c是编译语言。
java靠虚拟机,有内存回收机制;而c++看了之后,还是能明白对应的机器代码的。
你说c51的差别大于等于这两个,你说出他们的区别了吗?
〉这时候正常人的第一个想法难道不是移植
当然不是!除非是走量的产品,且价格有优势,这时正常人才会考虑移植。
可你上面提到的却是性能、升级。这和移植是不一样的。
〉对比一下两种......
-----------------------------------------------------------------------

如果你只是喜欢咬文嚼字,把目光盯紧对方言论的细节而非意义本身,那我也没办法

我所说的意思是,仅以语法而言,keil C 与标准 C 上的差距,仿佛 PHP 与标准 C 语法上的差距一样大——而且这确实是一种修辞手法,你要硬是打算一条条对比两边的差距,那我也只能由得你

我觉得很奇怪阿,你认为会需要介意个把 MCU 的性能和价差的产品,哪个是不走量的呢?另外,你觉得不改动外围硬件,只替换 MCU 器件、软件上增加新功能的的产品换代,就不能称为升级了么?莫非在你看来,产品升级就都得和电脑升级一样,开膛破肚大拆大换大折腾一番才算?

我索性也别闲扯了,测试代码放出来:

(标签在这个论坛没啥实际用,就只是标记一下开始结束)
volatile union {
        struct {
                unsigned b0_0:1;
                unsigned b1_2:2;
                unsigned b3_7:5;
        } _bit_fields;
        unsigned char _all_bits;
} _bit_test_0;

volatile unsigned char _bit_test_1;

volatile unsigned char a=1, b=2, c=14;

void main()
{
        _bit_test_0._bit_fields.b0_0 = a;
        _bit_test_0._bit_fields.b1_2 = b;
        _bit_test_0._bit_fields.b3_7 = c;

        _bit_test_0._bit_fields.b3_7 /= _bit_test_0._bit_fields.b1_2;

        _bit_test_1 = (a<<0) | (b<<1) | (c<<3);
        _bit_test_1 = (_bit_test_1 & 0b00000111) | ((((_bit_test_1>>3) & (0b00011111)) / ((_bit_test_1>>1) & (0b00000011)))<<3);
}


位操作理应做成易读的宏形式,不过因为纯粹只是个测试,就算了,如果有人喜欢在这点上抬杠,随意

您认为哪款编译器能把这段代码中 _bit_test_0 的运算操作翻译的比 _bit_test_1 的运算操作更简明更实惠,不妨拿来瞧瞧?

当然我估计您可能打算说,后一种做法相当于人工优化了——那是当然了,没有哪个编译器能比程序员更知道自己应该干什么吧?

ufbycd 发表于 2011-7-6 11:10:25

嗯,各有各的优点,各有各的缺点。存在自有它存在的道理,实现应用的时候合适的才是最好的。所以位域不会消亡,逻辑移位也有人用。
我觉得再讨论下去也没什么用了。

waitingconfirm 发表于 2011-7-6 11:16:49

哦,另外还得补充一句:

如果把上面这段代码用至少两个硬件体系下的编译器各自编译一遍,就能够看出更多差别来——后一种方式在不同体系编译器下,虽然汇编码本身肯定不同,但操作流程却非常相似,同在 CISC 体系处理器下,汇编指令条数也比较接近(我这里对比的就是 sdcc 和 gcc),而前者……好吧,如果相差 0.5 倍以上的指令条数差距也能无视的话,那我也不说什么了……

waitingconfirm 发表于 2011-7-6 11:20:23

回复【96楼】ufbycd
嗯,各有各的优点,各有各的缺点。存在自有它存在的道理,实现应用的时候合适的才是最好的。所以位域不会消亡,逻辑移位也有人用。
我觉得再讨论下去也没什么用了。
-----------------------------------------------------------------------

确实各有各的道理,否则也不会出现各个 C 编译器都把位域这种明显不符合标准的东西拿来实现这种实际情况存在了

讨论的意义在于:

不要让某一种做法变成一言堂,更不要让初学者以为谭浩强书中的套路就是绝对正确的,要学会质疑,要有自己的思想

dikex 发表于 2011-7-6 12:01:27

位域在MCU上的高效是得益于MCU的位操作指令,所以高效仅对单个位操作有效,多位操作肯定是麻烦的;以PIC18上面的MCC18编译器为例,操作单个位的汇编指令只要两句(MOVLB+BSF或BCF),但操作7个位(如unsigned a:7;)时则变成8句了(被分解为多句单个位操作了,MOVLB+7个BSF或BCF)

回复【95楼】waitingconfirm
回复【94楼】cliff   
感觉你说话不着边际啊
〉在我看来,keil c 本来就是披着 c 语言皮的“其它”语言,它与 c 语言之间的距离大致等同于 php 和 c 语言之间的距离……还要略大于 java 和 c++ 之间的距离……
php和c是什么距离,java和c++又是什么距离?
php是脚本语言;c是编译语言。
java靠虚拟机,有内存回收机制;而c++看了之后,还是能明白对应的机器代码的。
你说c51的差别大于等于这两个,你说出他们的区别了吗?
〉这时候正常人的第一个想法难道不是移植
当然不是!除非是走量的产品,且价格有优势,这时正常人才会考虑移植。
可你上面提到的却是性能、升级。这和移植是不一样的。
〉对比一下两种......
--------------------------------------------------------------......
-----------------------------------------------------------------------

esdart 发表于 2011-7-6 12:37:42

回复【83楼】Cliff
回复【81楼】esdart 依斯达特
回复【30楼】cliff   
&gt; 你花十分钟写的程序有可能几年后还有人在维护,给维护人员造成麻烦就是在浪费社会资源,浪费公司的效率。   
如果我写的程序,不是我来维护,而请别人维护,本身就是在浪费公司效率,浪费社会资源。   
-----------------------------------------------------------------------
员工离职再正常不过,如果你离职了,原公司还会让你维护吗?就算让你维护,你会去做吗?
-----------------------------------------------------------------------   
1、离职真的是正常不过的事情吗?在我看,不是的。人要有积累,才能有所作为。之所以频频离职,肯定有原因的。
2、与其花大代价做好让位置的人来......
-----------------------------------------------------------------------

您很适合当公司领导,我也很期待能有您这样的领导。可是事实上很多领导并不和您想的一样。您又会说,那种公司没有前途;我只能很无奈的回答,有前途的公司真的进不去。

Cliff 发表于 2011-7-6 13:25:16

回复【95楼】waitingconfirm

-----------------------------------------------------------------------

〉如果你只是喜欢咬文嚼字,把目光盯紧对方言论的细节而非意义本身,那我也没办法

可是在我感觉看来,你非常会使用文字游戏。而这种文字游戏,很可能会误导那些并不是“有自己的思想”(你98楼言论)的人。
比如:你说修辞手法,那是在你95楼,用了一个“仿佛”,可这个“仿佛”并没有出现在前面的帖子。你这“隐含”的仿佛,凭什么强加到其他人的头上呢?我没有理由相信,你前面用了一个隐含的“仿佛”。
在比如,“_bit_test_0 的运算操作翻译的比 _bit_test_1 的运算操作更简明更实惠”,我们要的不是“更简明”,而是“相当”。因为这两个操作是等价的。你要“更XXX”那就又是一种误导:只要编译器给出的代码没有“更简明更实惠”,那这个编译器就失败了。其实呢,不是这样的。
最后,你给的代码,也有误导的地方:
你用了 volatile,那么我问你:
_bit_test_0._bit_fields.b0_0 = a;
_bit_test_0._bit_fields.b1_2 = b;
_bit_test_0._bit_fields.b3_7 = c;



_bit_test_1 = (a<<0) | (b<<1) | (c<<3);

等价吗?
你这段测试代码本身就是不公平的。

Cliff 发表于 2011-7-6 13:26:01

回复【96楼】ufbycd
嗯,各有各的优点,各有各的缺点。存在自有它存在的道理,实现应用的时候合适的才是最好的。所以位域不会消亡,逻辑移位也有人用。
我觉得再讨论下去也没什么用了。
-----------------------------------------------------------------------

你这说法很“清朝”啊。
页: [1] 2
查看完整版本: 又是结构体,又外包共用体,这是什么意思呢?