找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1561|回复: 14
收起左侧

C语言代码中,能否有两个返回值?

[复制链接]
ID:624769 发表于 2021-11-17 16:24 | 显示全部楼层 |阅读模式
  比如一个子函数
char  TEST();
{
      char  a;
      a++;
      return a;
}

主程序中,  temp = Test();      就能取到 0x01

又比如:
bit  TEST2();
{
      bit  Flag;
      Flag = !Flag;
      return Flag;
}

主程序中,  temp_Flag = Test2();      就能取到 1

那么,能不能做一个子函数,同时返回一个 char 和 一个 bit  如果能的话,函数应该如何声明,主程序又该如何调用?

望知道的兄弟不吝赐教。
如果,明确确定不能实现,也望告知一下,我也就不浪费时间捉摸了。
回复

使用道具 举报

ID:824490 发表于 2021-11-17 17:20 | 显示全部楼层
返回用结构体,多少个都行。
回复

使用道具 举报

ID:155507 发表于 2021-11-17 20:18 | 显示全部楼层
return 语句可以有多个,可以出现在函数体的任意位置,但是每次调用函数只能有一个 return 语句被执行,所以只有一个返回值


函数多个参数传递方式:地址传递

void Exchg2(int *px, int *py)
{
   int tmp = *px;
   *px = *py;
   *py = tmp;
   printf("*px = %d, *py = %d.\n", *px, *py);
}
main()
{
   int a = 4;
   int b = 6;
   Exchg2(&a, &b);
   printf("a = %d, b = %d.\n”, a, b);
   return(0);
}
它的输出结果是:
*px = 6, *py = 4.
a = 6, b = 4.
看函数的接口部分:Exchg2(int *px, int *py),请注意:参数px、py都是指针。再看调用处:Exchg2(&a, &b);
它将a的地址(&a)代入到px,b的地址(&b)代入到py。同上面的值传递一样,函数调用时作了两个隐含的操作:将&a,&b的值赋值给了px、py。
   px = &a;
   py = &b;
呵呵!我们发现,其实它与值传递并没有什么不同,只不过这里是将a、b的地址值传递给了px、py,而不是传递的a、b的内容,而(请好好地在比较比较啦)整个Exchg2函数调用是如下执行的:
   px = &a; /* ← */
   py = &b; /* ← 请注意这两行,它是调用Exchg2的隐含动作。*/
   int tmp = *px;
   *px = *py;
   *py = tmp;
   printf("*px =%d, *py = %d.\n", *px, *py);
这样,有了头两行的隐含赋值操作。我们现在已经可以看出,指针px、py的值已经分别是a、b变量的地址值了。接下来,对*px、*py的操作当然也就是对a、b变量本身的操作了。所以函数里头的交换就是对a、b值的交换了,这就是所谓的地址传递(传递a、b的地址给了px、py),你现在明白了吗?

回复

使用道具 举报

ID:57657 发表于 2021-11-17 20:22 | 显示全部楼层
函数可以修改参数变量(数组)的值,需熟练指针操作。
回复

使用道具 举报

ID:213173 发表于 2021-11-17 21:24 | 显示全部楼层
可以有多个,但只能返回其中一个。
回复

使用道具 举报

ID:624769 发表于 2021-11-17 22:33 | 显示全部楼层
angmall 发表于 2021-11-17 20:18
return 语句可以有多个,可以出现在函数体的任意位置,但是每次调用函数只能有一个 return 语句被执行,所 ...

谢谢你的回答, 最近为了提高自己对C的理解,在重温以及改写以前的代码,由于这个传参问题当初也不知道黑51论坛,当初就是用的传指针方法。
但是传指针牵涉到指针类型什么的,所以当时为了考虑通用问题,都是用的通用指针 void *p, 所以给编译后的程序体积带来很大的负担。所以才想通过寄存器传参的方法,由于实际上子函数多是用汇编写的,所以其实无论是BYTE, 还是 BIT 其实都已经传到寄存器了,问题就是用在C语言中如何接收传出来的参。之前用比较变通的方法,先用一个  char Text(); 来接收存在R7的参, 再跟一个 Flag = CY; 把存在C的BIT参也读出来,感觉总不是很好,所以捉摸是不是可以有更好的办法。

看你指针说了那么多,想来应该指针这块比较了解,我也正好有指针问题相当疑惑,这里想请教一下,希望不吝赐教。
1) 当我声明一个   数组:  char data test_A[8]; 的时候,
函数, void test1(char *p)    应该是可以传  &test_A 的。
但是, 当我声明, 数组  char xdata test_B[8];  的时候,
函数, void  test2(这里怎么写?)   才能传 &test_B  ?
然后, 当我声明, 数组  char pdata test_C[8];  的时候,
函数, void  test3(这里怎么写?)   才能传 &test_C  ?

而,如果要强制用 上面 test2 函数 传 &test_C  又该在调用的时候怎么写?

2)我要声明一个指针  *p  指向 xdata 的话。
那么, char xdata *p 应该对的吧? 这种情况下 p 应该是双字节吧?毕竟xdata 地址是双字节吧? 而*p 应该是单字节的吧? 那么我在使用过程中,如果要让 *p 变成双字节, 这个强制转换应该怎么写?

暂时,想请教这两个问题,把指针稍微屡出一点头绪,后续可能还会追问,希望不要嫌弃。
对指针实在是很多不理解,所以很多时候都宁可不用指针,而用数组。
回复

使用道具 举报

ID:401564 发表于 2021-11-17 23:49 | 显示全部楼层
沙发已经告诉你了,用结构体可以返回多个数据类型,N个!结构体还有一个好处,就是复制,数据A的数据如果要复制到数组B的话,是不能B=A的,是有点麻烦的
但结构体可以直接用  B=A;
bit是,位不能作为结构体成员,别的单片机不知道,至少8051是不行的,但可以用一个char 来代替的,速度和代码空间变化不大
不要管xdata,不要管R7,这是C语言,不是汇编,都这样想,不会汇编的人都写不出C程序来了,至于8051的16位指针,在C中用到的人少到几乎没有.
你在数据前面加了xdata,编译器自然会按照xdata来寻址,
那128个字节做不也什么事的,很多时候是不够用的,但编译器会自动处理的typedef struct
{
        unsigned char a;
        char k;
} stru;          
stru disp(unsigned char m)
{
stru p;
p.a=m+1;
p.k=m+10;
return p;
}
void main()
{
    unsigned char a,b;
        stru m;
        m=disp(5);
        a=m.a;
        b=m.k;
    while(1);
}


回复

使用道具 举报

ID:624769 发表于 2021-11-18 00:19 | 显示全部楼层
Y_G_G 发表于 2021-11-17 23:49
沙发已经告诉你了,用结构体可以返回多个数据类型,N个!结构体还有一个好处,就是复制,数据A的数据如果要复制 ...

谢谢 答复, 经你上次一说,我打算恶补一下C语言,
这里,我想请教一下:

        m=disp(5);            是不是执行这句的时候, 把p.a  p.k 算出来,然后存在一个地方
        a=m.a;                  这里两句,就把,上面算出来值,赋给a,b
        b=m.k;

如果,我这里再运行一个
       x=disp(8);
      上面, m.a, m.k 不会受影响。 新的结果在 x.a, x.k?

判答。
回复

使用道具 举报

ID:401564 发表于 2021-11-18 00:37 | 显示全部楼层
unsigned char a,b;  
        stru m;//声明结结构体m,m有两个成员,就是前面已经标记过的unsigned char a;        char k;        m=disp(5);//参考函数声明中的执行
        a=m.a;//结构体成员a的值赋值到变量a,两个a是不一样的,结构体a跟下面的k同理
        b=m.k;


如果前面有这样的声明stru m,x;
那么,这就是有两个结构体了:m和x,
x=disp(8);//这个只会改变x.a, x.k,m不变
m=disp(1);//这个只会改变m.a, m.k,x不变
x=m;//结构体m赋值到x
等同于:
x.a=m.a;
x.k=m.k;
如果成员很多,或者是在结构体中有数组,x=m;这种操作就相当方便
验证的最好办法是仿真或者通过串口在电脑显示
回复

使用道具 举报

ID:584195 发表于 2021-11-18 06:53 | 显示全部楼层
看着有点蒙。
回复

使用道具 举报

ID:155507 发表于 2021-11-18 08:07 | 显示全部楼层
188610329 发表于 2021-11-17 22:33
谢谢你的回答, 最近为了提高自己对C的理解,在重温以及改写以前的代码,由于这个传参问题当初也不知道黑 ...

  1. #include <reg52.h>
  2. #define uint unsigned int
  3. #define uchar unsigned char

  4. char data test_A[8];
  5. char xdata test_B[8];
  6. char pdata test_C[8];

  7. void test1(char *p);
  8. void test2(char xdata *p1);
  9. void test3(char pdata *p2);

  10. void test1(char *p)
  11. {
  12.         *p =0x01;
  13. }

  14. void test2(char xdata *p1)
  15. {
  16.                 *p1 =0x02;
  17. }
  18. void test3(char pdata *p2)
  19. {
  20.                 *p2 =0x03;
  21. }

  22. void main()
  23. {
  24.         test1(test_A);
  25.         test2(test_B);
  26.         test3(test_C);
  27.         test2(test_B);
  28.         test2((char xdata *)test_C);
  29.         test2((char xdata *)test_A);
  30. }
复制代码

  1. C51 COMPILER V9.60.0.0   TEST12                                                            11/18/2021 07:57:43 PAGE 1   


  2. C51 COMPILER V9.60.0.0, COMPILATION OF MODULE TEST12
  3. OBJECT MODULE PLACED IN .\Objects\test12.obj
  4. COMPILER INVOKED BY: C:\Keil_v5\C51\BIN\C51.EXE test12.c OPTIMIZE(8,SPEED) BROWSE DEBUG OBJECTEXTEND CODE SYMBOLS PRINT(
  5.                     -.\Listings\test12.lst) TABS(2) OBJECT(.\Objects\test12.obj)

  6. line level    source

  7.    1          /*
  8.    2          看你指针说了那么多,想来应该指针这块比较了解,我也正好有指针问题相当疑捊             -ƒ‘,这里想请教一下,希望不吝赐教。
  9.    3          1) 当我声明一个   数组:  char data test_A[8]; 的时候,
  10.    4          函数, void test1(char *p)    应该是可以传  &test_A 的。
  11.    5          但是, 当我声明, 数组  char xdata test_B[8];  的时候,
  12.    6          函数, void  test2(这里怎么写?)   才能传 &test_B  ?
  13.    7          然后, 当我声明, 数组  char pdata test_C[8];  的时候,
  14.    8          函数, void  test3(这里怎么写?)   才能传 &test_C  ?
  15.    9         
  16.   10          而,如果要强制用 上面 test2 函数 传 &test_C  又该在调用的时候怎么写?
  17.   11         
  18.   12          2)我要声明一个指针  *p  指向 xdata 的话。
  19.   13          那么, char xdata *p 应该对的吧? 这种情况下 p 应该是双字节吧?毕竟xdata 地址是
  20.              -双字节吧? 而*p 应该是单字节的吧? 那么我在使用过程中,如果要让 *p 变成双字节, 这不
  21.              -a强制转换应该怎么写?
  22.   14         
  23.   15          暂时,想请教这两个问题,把指针稍微屡出一点头绪,后续可能还会追问,希望䍊             -¸要嫌弃。
  24.   16          对指针实在是很多不理解,所以很多时候都宁可不用指针,而用数组。
  25.   17         
  26.   18          */
  27.   19          #include <reg52.h>
  28.   20          #define uint unsigned int
  29.   21          #define uchar unsigned char
  30.   22         
  31.   23          char data test_A[8];
  32.   24          char xdata test_B[8];
  33.   25          char pdata test_C[8];
  34.   26         
  35.   27          void test1(char *p);
  36.   28          void test2(char xdata *p1);
  37.   29          void test3(char pdata *p2);
  38.   30         
  39.   31          void test1(char *p)
  40.   32          {
  41.   33   1        *p =0x01;
  42.   34   1      }
  43.   35         
  44.   36          void test2(char xdata *p1)
  45.   37          {
  46.   38   1          *p1 =0x02;
  47.   39   1      }
  48.   40          void test3(char pdata *p2)
  49.   41          {
  50.   42   1          *p2 =0x03;
  51.   43   1      }
  52.   44         
  53.   45          void main()
  54.   46          {
  55.   47   1        test1(test_A);
  56.   48   1        test2(test_B);
  57.   49   1        test3(test_C);
  58.   50   1        test2(test_B);
  59. C51 COMPILER V9.60.0.0   TEST12                                                            11/18/2021 07:57:43 PAGE 2   

  60.   51   1        test2((char xdata *)test_C);
  61.   52   1        test2((char xdata *)test_A);
  62.   53   1      }
  63.   54         
  64.   55         
  65.   56         
  66.   57         
  67.   58         
  68. C51 COMPILER V9.60.0.0   TEST12                                                            11/18/2021 07:57:43 PAGE 3   

  69. ASSEMBLY LISTING OF GENERATED OBJECT CODE


  70.              ; FUNCTION _test1 (BEGIN)
  71.                                            ; SOURCE LINE # 31
  72. ;---- Variable 'p' assigned to Register 'R1/R2/R3' ----
  73.                                            ; SOURCE LINE # 32
  74.                                            ; SOURCE LINE # 33
  75. 0000 7401              MOV     A,#01H
  76. 0002 020000      E     LJMP    ?C?CSTPTR
  77.              ; FUNCTION _test1 (END)

  78.              ; FUNCTION _test2 (BEGIN)
  79.                                            ; SOURCE LINE # 36
  80. ;---- Variable 'p1' assigned to Register 'DPTR' ----
  81. 0000 8F82              MOV     DPL,R7
  82. 0002 8E83              MOV     DPH,R6
  83.                                            ; SOURCE LINE # 37
  84.                                            ; SOURCE LINE # 38
  85. 0004 7402              MOV     A,#02H
  86. 0006 F0                MOVX    @DPTR,A
  87.                                            ; SOURCE LINE # 39
  88. 0007 22                RET     
  89.              ; FUNCTION _test2 (END)

  90.              ; FUNCTION _test3 (BEGIN)
  91.                                            ; SOURCE LINE # 40
  92. ;---- Variable 'p2' assigned to Register 'R0' ----
  93. 0000 A807              MOV     R0,AR7
  94.                                            ; SOURCE LINE # 41
  95.                                            ; SOURCE LINE # 42
  96. 0002 7403              MOV     A,#03H
  97. 0004 F2                MOVX    @R0,A
  98.                                            ; SOURCE LINE # 43
  99. 0005 22                RET     
  100.              ; FUNCTION _test3 (END)

  101.              ; FUNCTION main (BEGIN)
  102.                                            ; SOURCE LINE # 45
  103.                                            ; SOURCE LINE # 46
  104.                                            ; SOURCE LINE # 47
  105. 0000 7B00              MOV     R3,#00H
  106. 0002 7A00        R     MOV     R2,#HIGH test_A
  107. 0004 7900        R     MOV     R1,#LOW test_A
  108. 0006 120000      R     LCALL   _test1
  109.                                            ; SOURCE LINE # 48
  110. 0009 7E00        R     MOV     R6,#HIGH test_B
  111. 000B 7F00        R     MOV     R7,#LOW test_B
  112. 000D 120000      R     LCALL   _test2
  113.                                            ; SOURCE LINE # 49
  114. 0010 7F00        R     MOV     R7,#LOW test_C
  115. 0012 120000      R     LCALL   _test3
  116.                                            ; SOURCE LINE # 50
  117. 0015 7F00        R     MOV     R7,#LOW test_B
  118. 0017 120000      R     LCALL   _test2
  119.                                            ; SOURCE LINE # 51
  120. 001A 7E00        R     MOV     R6,#HIGH test_C  <---应该是双字节
  121. 001C 7F00        R     MOV     R7,#LOW test_C
  122. 001E 120000      R     LCALL   _test2
  123.                                            ; SOURCE LINE # 52
  124. 0021 7E00        R     MOV     R6,#HIGH test_A  <---应该是双字节
  125. 0023 7F00        R     MOV     R7,#LOW test_A
  126. C51 COMPILER V9.60.0.0   TEST12                                                            11/18/2021 07:57:43 PAGE 4   

  127. 0025 020000      R     LJMP    _test2
  128.              ; FUNCTION main (END)

  129. C51 COMPILER V9.60.0.0   TEST12                                                            11/18/2021 07:57:43 PAGE 5   

  130. NAME                                    CLASS   MSPACE  TYPE    OFFSET  SIZE
  131. ====                                    =====   ======  ====    ======  ====


  132. P1 . . . . . . . . . . . . . . . . . .  SFR      DATA   U_CHAR   0090H  1
  133. P3 . . . . . . . . . . . . . . . . . .  SFR      DATA   U_CHAR   00B0H  1
  134. IE . . . . . . . . . . . . . . . . . .  SFR      DATA   U_CHAR   00A8H  1
  135. IP . . . . . . . . . . . . . . . . . .  SFR      DATA   U_CHAR   00B8H  1
  136. main . . . . . . . . . . . . . . . . .  PUBLIC   CODE   PROC     0000H  -----
  137. SCON . . . . . . . . . . . . . . . . .  SFR      DATA   U_CHAR   0098H  1
  138. TCON . . . . . . . . . . . . . . . . .  SFR      DATA   U_CHAR   0088H  1
  139. test_A . . . . . . . . . . . . . . . .  PUBLIC   DATA   ARRAY    0000H  8
  140. test_B . . . . . . . . . . . . . . . .  PUBLIC   XDATA  ARRAY    0000H  8
  141. test_C . . . . . . . . . . . . . . . .  PUBLIC   PDATA  ARRAY    0000H  8
  142. T2CON. . . . . . . . . . . . . . . . .  SFR      DATA   U_CHAR   00C8H  1
  143. _test1 . . . . . . . . . . . . . . . .  PUBLIC   CODE   PROC     0000H  -----
  144.   p. . . . . . . . . . . . . . . . . .  * REG *  DATA   PTR      0001H  3
  145. _test2 . . . . . . . . . . . . . . . .  PUBLIC   CODE   PROC     0000H  -----
  146.   p1 . . . . . . . . . . . . . . . . .  * REG *  DATA   PTR      0082H  2
  147. _test3 . . . . . . . . . . . . . . . .  PUBLIC   CODE   PROC     0000H  -----
  148.   p2 . . . . . . . . . . . . . . . . .  * REG *  DATA   PTR      0000H  1
  149. PSW. . . . . . . . . . . . . . . . . .  SFR      DATA   U_CHAR   00D0H  1


  150. MODULE INFORMATION:   STATIC OVERLAYABLE
  151.    CODE SIZE        =     59    ----
  152.    CONSTANT SIZE    =   ----    ----
  153.    XDATA SIZE       =      8    ----
  154.    PDATA SIZE       =      8    ----
  155.    DATA SIZE        =      8    ----
  156.    IDATA SIZE       =   ----    ----
  157.    BIT SIZE         =   ----    ----
  158. END OF MODULE INFORMATION.


  159. C51 COMPILATION COMPLETE.  0 WARNING(S),  0 ERROR(S)
复制代码
回复

使用道具 举报

ID:824490 发表于 2021-11-18 10:59 | 显示全部楼层
//给你一个简易代码:
#include "Reg51.H"

typedef struct {
  unsigned char G;
  unsigned char R;
  unsigned char B;
}ColorVal ;   //声明一个结构体,包含3个成员;
  

ColorVal changeVal (ColorVal mydata); //结构体成员互换
  
void main()
{

ColorVal temp1;//定义一个结构体

temp1.G=10;temp1.R=20;temp1.B=30; //初始赋值

while(1)

{

   temp1= changeVal(temp1); //互换
         
   P1=temp1.R;  //观察结果
         P2=temp1.G;
         P3=temp1.B;
         
  }

}


  ColorVal changeVal (ColorVal mydata)
  {
   unsigned char tt;
    tt= mydata.R;
    mydata.R=mydata.B;
    mydata.B=mydata.G;
    mydata.G=tt;
         return mydata; //返回值为结构体:带3个参数
               
   }
  
  
回复

使用道具 举报

ID:624769 发表于 2021-11-18 11:29 | 显示全部楼层

谢谢, 感觉有一些启发, 但是又抓不住, 我先消化一下, 可能消化完了, 还要再请教一下,  另外, 两个题外问题。
1)
void main()
{
        test1(test_A);   
        test2(test_B);
        test3(test_C);    < = 这几个地方,应该是要传地址,从你翻出来的汇编代码看,也确实是传得地址,但是,为什么不需要用 &test_A 是因为数组的关系么?有什么特别的规定么?

2) 你这个翻译汇编,好像是工具生成的,用什么工具的?

回复

使用道具 举报

ID:624769 发表于 2021-11-18 11:31 | 显示全部楼层
Y_G_G 发表于 2021-11-18 00:37
unsigned char a,b;  
        stru m;//声明结结构体m,m有两个成员,就是前面已经标记过的unsigned char a ...

谢谢, 科普了一些结构体的知识, 我消化消化,估计,稍后还要麻烦你。
回复

使用道具 举报

ID:155507 发表于 2021-11-18 16:14 | 显示全部楼层
188610329 发表于 2021-11-18 11:29
谢谢, 感觉有一些启发, 但是又抓不住, 我先消化一下, 可能消化完了, 还要再请教一下,  另外, 两个题外问 ...

1)不需要用 &test_A 是因为数组的关系
http://c.biancheng.net/cpp/html/61.html

2) 就是 Keil
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表