c - 从16位地址中划分高/低字节的方法?

标签 c 8051 sdcc keil

我正在 8051 处理器上开发软件。一个经常做的工作就是对一个16bit地址进行高低字节的划分。我想看看有多少种方法可以实现。到目前为止我提出的方法是:(比如 ptr 是一个 16 位指针,int 是 16 位 int)[注意 rn 和 arn 是寄存器]

位运算

ADDH = (unsigned int) ptr >> 8;
ADDL = (unsigned int) ptr & 0x00FF;

SDCC给出如下汇编代码


;   t.c:32: ADDH = (unsigned int) ptr >> 8;
    mov ar6,r3
    mov ar7,r4
    mov _main_ADDH_1_1,r7
;   t.c:33: ADDL = (unsigned int) ptr & 0x00FF;
    mov _main_ADDL_1_1,r6
Keil C51 给我:

                                           ; SOURCE LINE # 32
0045 AA00        R     MOV     R2,ptr+01H
0047 A900        R     MOV     R1,ptr+02H
0049 AE02              MOV     R6,AR2
004B EE                MOV     A,R6
004C F500        R     MOV     ADDH,A
                                           ; SOURCE LINE # 33
004E AF01              MOV     R7,AR1
0050 EF                MOV     A,R7
0051 F500        R     MOV     ADDL,A
其中有许多无用的代码恕我直言。

指针技巧


ADDH = ((unsigned char *)&ptr)[0];
ADDL = ((unsigned char *)&ptr)[1];
SDCC 给我:

;   t.c:37: ADDH = ((unsigned char *)&ptr)[0];
    mov _main_ADDH_1_1,_main_ptr_1_1
;   t.c:38: ADDL = ((unsigned char *)&ptr)[1];
    mov _main_ADDL_1_1,(_main_ptr_1_1 + 0x0001)
Keil C51 给我:

                                           ; SOURCE LINE # 37
006A 850000      R     MOV     ADDH,ptr
                                           ; SOURCE LINE # 38
006D 850000      R     MOV     ADDL,ptr+01H
与SDCC版本相同。

Andrey 的数学方法


 ADDH = ptr / 256;
 ADDL = ptr % 256;

SDCC 给出:


;   t.c:42: ADDH = (unsigned int)ptr / 256;
    mov ar5,r3
    mov ar6,r4
    mov ar7,r6
    mov _main_ADDH_1_1,r7
;   t.c:43: ADDL = (unsigned int)ptr % 256;
    mov _main_ADDL_1_1,r5
我不知道为什么 sdcc 使用 r7 寄存器... Keil C51 给我:

                                           ; SOURCE LINE # 42
0079 AE00        R     MOV     R6,ptr
007B AF00        R     MOV     R7,ptr+01H
007D AA06              MOV     R2,AR6
007F EA                MOV     A,R2
0080 F500        R     MOV     ADDH,A
                                           ; SOURCE LINE # 43
0082 8F00        R     MOV     ADDL,R7
我不知道为什么 Keil 也不使用 R2 寄存器...

semaj 的 union 方法


typedef union
   {
   unsigned short u16;
   unsigned char u8[2];
   } U16_U8;<p></p>

<p>U16_U8 ptr;</p>

<p>// Do something to set the variable ptr
ptr.u16 = ?;</p>

<p>ADDH = ptr.u8[0];
ADDL = ptr.u8[1];
</p>

SDCC 给我


;   t.c:26: ADDH = uptr.u8[0];
    mov _main_ADDH_1_1,_main_uptr_1_1
;   t.c:27: ADDL = uptr.u8[1];
    mov _main_ADDL_1_1,(_main_uptr_1_1 + 0x0001)
Keil C51 给我:

                                           ; SOURCE LINE # 26
0028 850000      R     MOV     ADDH,uptr
                                           ; SOURCE LINE # 27
002B 850000      R     MOV     ADDL,uptr+01H
这对指针技巧非常微笑。但是,这种方法需要多两个字节的内存来存储 union 。

有没有人有任何其他好主意? ;)

谁能告诉我哪种方式更有效?

如果有人感兴趣,这里是测试用例:


typedef union
{
    unsigned short u16;
    unsigned char u8[2];
} U16_U8;<p></p>

<p>// call a function on the ADDs to avoid optimizition
void swap(unsigned char *a, unsigned char *b)
{
    unsigned char tm;
    tm = *a;
    *a = *b;
    *b = tm;
}</p>

<p>main (void)
{
    char c[] = "hello world.";
    unsigned char xdata *ptr = (unsigned char xdata *)c;
    unsigned char ADDH, ADDL;
    unsigned char i = 0;</p>

<pre><code>U16_U8 uptr;
uptr.u16 = (unsigned short)ptr;

for ( ; i < 4 ; i++, uptr.u16++){
    ADDH = uptr.u8[0];
    ADDL = uptr.u8[1];
    swap(&ADDH, &ADDL);
}

for ( ; i < 4 ; i++, ptr++){
    ADDH = (unsigned int) ptr >> 8;
    ADDL = (unsigned int) ptr & 0x00FF;
    swap(&ADDH, &ADDL);
}
for ( ; i < 4 ; i++, ptr++){
    ADDH = ((unsigned char *)&ptr)[0];
    ADDL = ((unsigned char *)&ptr)[1];
    swap(&ADDH, &ADDL);
}
for ( ; i < 4 ; i++, ptr++){
    ADDH = (unsigned int)ptr / 256;
    ADDL = (unsigned int)ptr % 256;
    swap(&ADDH, &ADDL);
}
</code></pre>

<p>}
</p>

最佳答案

最高效的方式是完全依赖于编译器。您肯定必须弄清楚如何从您的编译器获取 8051 项目的汇编列表。

您可以尝试的一种与已经提到的方法类似的方法是 union :

typedef union
   {
   unsigned short u16;
   unsigned char u8[2];
   } U16_U8;

U16_U8 ptr;

// Do something to set the variable ptr
ptr.u16 = ?;

ADDH = ptr.u8[0];
ADDL = ptr.u8[1];

关于c - 从16位地址中划分高/低字节的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2538614/

相关文章:

c++ - 在 Visual Studio 调试器中查看数组?

c - 为什么在这种特定情况下在堆栈上分配一个大元素不会失败?

c - 8051 的 sdcc 编译器的奇怪行为

c - 指向结构的指针成员

c - SDCC/GBDK,将结构数组传递给函数

java - JNI 中 unsigned char 指针的等价物是什么?

c - 信号处理程序不会看到全局变量

assembly - 写一个延迟子程序?

c - 在 Visual Studio 2010 中使用 SDCC?