今天要在linux下搞音频编程,在网上查阅了一下资料,网上很多资料都是在linux下直接对/dev/dsp进行编程的,因为在以往的linux系统中,我们是可以通过cat  xxx.wav /dev/dsp 来很容易的播放一个音频文件,在应用程序中,也可以直接操作/dev/dsp,实现声音的播放:打开->写入(实际上就能播放)->关闭。

然而在换成了ubuntu-12.04 LST后,我发现/dev中根本找不到dsp,之前直接操作/dev/dsp的程序都无法正常运行,而是 can't find /dev/dsp.

经过我再三查找,发现现在基本上都不用dsp了,大多数人都在用ALSA音频编程(其实我也是个菜鸟)。首先介绍一下一些关于ALSA编程的知识:

1、GNU/Linux 系统下三大主流声卡驱动程序集:
Linux 有三个主流的声卡驱动程序集:OSS/Lite(也称为OSS/Free)、OSS/Full
(商业软件)、ALSA(自由软件)。
 
OSS/Lite 是现在linux内核中自带的声卡驱动程序集,最初由 Hannu Savolainen
开发。后来 Hannu 跑去开发 Open Sound System(也就是上面所说的OSS/Full)。
由于 Hannu 的“逃跑”,RH 资助 Alan Cox 增强 Hannu 开发的驱动程序,并使它们
完全模块化。现在 Alan Cox 是内核声卡驱程集的维护人。OSS/Lite 从kernel-2.0开
始并入内核,现在大家使用的声卡驱程默认都是OSS/Lite中的。
 
OSS/Full 是由 4Front Technologies 开发并销售的商业软件。它可以驱动很多
声卡并且可以用在很多 UNIX 系统中。OSS/Full 完全兼容以前基于 OSS/Lite 开发
的应用程序。作为一个商业软件,你虽然可以使用它,但是你得不到它的源代码,并且
你必须为此而付钱。
 
ALSA 是linux内核的下一代标准声卡驱动集。开始时 Jaroslav Kysela 等人为
Gravis UltraSound Card 开发驱动程序,后来该计划改名为 ALSA「先进的linux音频
体系」,因为他们认为 ALSA 比原来内核中的 OSS/Lite 驱动程序集更优秀,完全可以
代替 OSS/Lite。他们是对的,ALSA 支持的声卡比 OSS/Lite 多,完全兼容以前基于
OSS 开发的程序,SMP(多处理器) 与 线程安全设计,并且从 2.5 分支的内核开始,
ALSA 的驱动程序集开始并入内核,大家可以在今年的 2.6 版本的内核中看到使用它们。
 
2、为什么要使用 ALSA 开发音频程序
首先,ALSA 是 linux 以后声卡驱动程序的标准,OSS/Lite 迟早会从内核中去除。
开发基于 ALSA 的音频程序可以保证以后的兼容。
其次,我们简单比较一下开发基于 OSS 与 ALSA 的方法。
OSS 向应用程序提供了一系列的系统接口。开发基于 OSS 的应用程序需要使用
open,close,ioctl,read,write 等低级系统调用来完成音频设备的控制、音频流的输入
输出。
而 ALSA 则为应用程序开发人员提供了一个优秀的音频库。利用该音频库,开发
人员可以方便快捷地开发出自己的应用程序,细节则留给音频库内部处理。当然 ALSA
也提供了类似于 OSS 的系统接口,不过 ALSA 的开发者建议应用程序开发者使用音频
库而不是驱程API。
 
3、那么我该从何开始呢
第一步当然是安装 ALSA 驱动程序与音频库。
当前 ALSA 有两个分支,一个是以前的0.5版本,一个是现在的0.9。ALSA的开发者
已经不支持0.5版本了,所以我们要使用0.9。大家可以在 ALSA 的主页
www.alsa-project.org 上下载安装。这个页面上的信息对大家安装很有用:
www.alsa-project.org/alsa-doc ,建议先浏览一下。
 
第二步是参考文档与例子。
在 ALSA 的文档页面上有两篇为应用程序开发者提供的文章:
Howto use the ALSA API [
http://www.op.net/~pbd/alsa-audio.html ]
当然,还有音频库API的在线参考:
 
 要是你已经完成以上几步的话,那么你就应该开始开发了。
4. ALSA设备文件结构

我们从alsa在Linux中的设备文件结构开始我们的alsa之旅. 看看我的电脑中的alsa驱动的设备文件结构:

  1. $ cd /dev/snd
  2. $ ls -l
  3.  
  4. crw-rw----+ root audio , -- : controlC0
  5. crw-rw----+ root audio , -- : midiC0D0
  6. crw-rw----+ root audio , -- : pcmC0D0c
  7. crw-rw----+ root audio , -- : pcmC0D0p
  8. crw-rw----+ root audio , -- : pcmC0D1p
  9. crw-rw----+ root audio , -- : seq
  10. crw-rw----+ root audio , -- : timer
  11. $

我们可以看到以下设备文件:

  1. controlC0 --> 用于声卡的控制,例如通道选择,混音,麦克风的控制等
  2. midiC0D0 --> 用于播放midi音频
  3. pcmC0D0c --〉 用于录音的pcm设备
  4. pcmC0D0p --〉 用于播放的pcm设备
  5. seq --〉 音序器
  6. timer --〉 定时器

其中,C0D0代表的是声卡0中的设备0,pcmC0D0c最后一个c代表capture,pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则。从上面的列表可以看出,我的声卡下挂了6个设备,根据声卡的实际能力,驱动实际上可以挂上更多种类的设备,在include/sound/core.h中,定义了以下设备类型:

  1. #define SNDRV_DEV_TOPLEVEL ((__force snd_device_type_t) 0)
    #define SNDRV_DEV_CONTROL ((__force snd_device_type_t) 1)
    #define SNDRV_DEV_LOWLEVEL_PRE ((__force snd_device_type_t) 2)
    #define SNDRV_DEV_LOWLEVEL_NORMAL ((__force snd_device_type_t) 0x1000)
    #define SNDRV_DEV_PCM ((__force snd_device_type_t) 0x1001)
    #define SNDRV_DEV_RAWMIDI ((__force snd_device_type_t) 0x1002)
    #define SNDRV_DEV_TIMER ((__force snd_device_type_t) 0x1003)
    #define SNDRV_DEV_SEQUENCER ((__force snd_device_type_t) 0x1004)
    #define SNDRV_DEV_HWDEP ((__force snd_device_type_t) 0x1005)
    #define SNDRV_DEV_INFO ((__force snd_device_type_t) 0x1006)
    #define SNDRV_DEV_BUS ((__force snd_device_type_t) 0x1007)
    #define SNDRV_DEV_CODEC ((__force snd_device_type_t) 0x1008)
    #define SNDRV_DEV_JACK ((__force snd_device_type_t) 0x1009)
    #define SNDRV_DEV_LOWLEVEL ((__force snd_device_type_t) 0x2000)  

通常,我们更关心的是pcm和control这两种设备。

5.一些例子,这些例子在官方文档也有,请自行查阅

1.)显示一些PCM的类型和格式:
  1. #include <iostream>
  2. #include <alsa/asoundlib.h>
  3.  
  4. int main()
  5. {
  6. std::cout << "ALSA library version: " << SND_LIB_VERSION_STR << std::endl;
  7.  
  8. std::cout << "PCM stream types: " << std::endl;
  9.  
  10. for (int val=; val <= SND_PCM_STREAM_LAST; ++val)
  11. std::cout << snd_pcm_stream_name((snd_pcm_stream_t)val) << std::endl;
  12. std::cout << std::endl;
  13.  
  14. std::cout << "PCM access types: " << std::endl;
  15. for (int val=; val <= SND_PCM_ACCESS_LAST; ++val)
  16. std::cout << snd_pcm_access_name((snd_pcm_access_t)val) << std::endl;
  17. std::cout << std::endl;
  18.  
  19. std::cout << "PCM subformats: " << std::endl;
  20. for (int val=; val <= SND_PCM_SUBFORMAT_LAST; ++val)
  21. std::cout << snd_pcm_subformat_name((snd_pcm_subformat_t)val) << " (" << snd_pcm_subformat_description((snd_pcm_subformat_t)val) << ")" << std::endl;
  22. std::cout << std::endl;
  23.  
  24. std::cout << "PCM states: " << std::endl;
  25. for (int val=; val <= SND_PCM_STATE_LAST; ++val)
  26. std::cout << snd_pcm_state_name((snd_pcm_state_t)val) << std::endl;
  27. std::cout << std::endl;
  28.  
  29. std::cout << "PCM formats: " << std::endl;
  30. for (int val=; val <= SND_PCM_FORMAT_LAST; ++val)
  31. std::cout << snd_pcm_format_name((snd_pcm_format_t)val) << " (" << snd_pcm_format_description((snd_pcm_format_t)val) << ")" << std::endl;
  32. std::cout << std::endl;
  33.  
  34. }
2.)打开PCM设备和设置参数
  1. #include <iostream>
  2. #include <alsa/asoundlib.h>
  3.  
  4. int main()
  5. {
  6. int rc;
  7. snd_pcm_t* handle;
  8. snd_pcm_hw_params_t* params;
  9. unsigned int val, val2;
  10. int dir;
  11. snd_pcm_uframes_t frames;
  12.  
  13. if ( (rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, )) < )
  14. {
  15. std::cerr << "unable to open pcm devices: " << snd_strerror(rc) << std::endl;
  16. exit();
  17. }
  18.  
  19. snd_pcm_hw_params_alloca(&params);
  20.  
  21. snd_pcm_hw_params_any(handle, params);
  22.  
  23. snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
  24.  
  25. snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
  26.  
  27. snd_pcm_hw_params_set_channels(handle, params, );
  28.  
  29. val = ;
  30.  
  31. snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
  32.  
  33. if ( (rc = snd_pcm_hw_params(handle, params)) < )
  34. {
  35. std::cerr << "unable to set hw parameters: " << snd_strerror(rc) << std::endl;
  36. exit();
  37. }
  38.  
  39. std::cout << "PCM handle name = " << snd_pcm_name(handle) << std::endl;
  40.  
  41. std::cout << "PCM state = " << snd_pcm_state_name(snd_pcm_state(handle)) << std::endl;
  42.  
  43. snd_pcm_hw_params_get_access(params, (snd_pcm_access_t *)&val);
  44.  
  45. std::cout << "access type = " << snd_pcm_access_name((snd_pcm_access_t)val) << std::endl;
  46.  
  47. snd_pcm_hw_params_get_format(params, (snd_pcm_format_t*)(&val));
  48.  
  49. std::cout << "format = '" << snd_pcm_format_name((snd_pcm_format_t)val) << "' (" << snd_pcm_format_description((snd_pcm_format_t)val) << ")" << std::endl;
  50.  
  51. snd_pcm_hw_params_get_subformat(params, (snd_pcm_subformat_t *)&val);
  52. std::cout << "subformat = '" <<
  53. snd_pcm_subformat_name((snd_pcm_subformat_t)val) << "' (" << snd_pcm_subformat_description((snd_pcm_subformat_t)val) << ")" << std::endl;
  54.  
  55. snd_pcm_hw_params_get_channels(params, &val);
  56. std::cout << "channels = " << val << std::endl;
  57.  
  58. snd_pcm_hw_params_get_rate(params, &val, &dir);
  59. std::cout << "rate = " << val << " bps" << std::endl;
  60.  
  61. snd_pcm_hw_params_get_period_time(params, &val, &dir);
  62. std::cout << "period time = " << val << " us" << std::endl;
  63.  
  64. snd_pcm_hw_params_get_period_size(params, &frames, &dir);
  65. std::cout << "period size = " << static_cast<int>(frames) << " frames" << std::endl;
  66.  
  67. snd_pcm_hw_params_get_buffer_time(params, &val, &dir);
  68. std::cout << "buffer time = " << val << " us" << std::endl;
  69.  
  70. snd_pcm_hw_params_get_buffer_size(params, (snd_pcm_uframes_t *) &val);
  71. std::cout << "buffer size = " << val << " frames" << std::endl;
  72.  
  73. snd_pcm_hw_params_get_periods(params, &val, &dir);
  74. std::cout << "periods per buffer = " << val << " frames" << std::endl;
  75.  
  76. snd_pcm_hw_params_get_rate_numden(params, &val, &val2);
  77. std::cout << "exact rate = " << val/val2 << " bps" << std::endl;
  78.  
  79. val = snd_pcm_hw_params_get_sbits(params);
  80. std::cout << "significant bits = " << val << std::endl;
  81.  
  82. snd_pcm_hw_params_get_tick_time(params, &val, &dir);
  83. std::cout << "tick time = " << val << " us" << std::endl;
  84.  
  85. val = snd_pcm_hw_params_is_batch(params);
  86. std::cout << "is batch = " << val << std::endl;
  87.  
  88. val = snd_pcm_hw_params_is_block_transfer(params);
  89. std::cout << "is block transfer = " << val << std::endl;
  90.  
  91. val = snd_pcm_hw_params_is_double(params);
  92. std::cout << "is double = " << val << std::endl;
  93.  
  94. val = snd_pcm_hw_params_is_half_duplex(params);
  95. std::cout << "is half duplex = " << val << std::endl;
  96.  
  97. val = snd_pcm_hw_params_is_joint_duplex(params);
  98. std::cout << "is joint duplex = " << val << std::endl;
  99.  
  100. val = snd_pcm_hw_params_can_overrange(params);
  101. std::cout << "can overrange = " << val << std::endl;
  102.  
  103. val = snd_pcm_hw_params_can_mmap_sample_resolution(params);
  104. std::cout << "can mmap = " << val << std::endl;
  105.  
  106. val = snd_pcm_hw_params_can_pause(params);
  107. std::cout << "can pause = " << val << std::endl;
  108.  
  109. val = snd_pcm_hw_params_can_resume(params);
  110. std::cout << "can resume = " << val << std::endl;
  111.  
  112. val = snd_pcm_hw_params_can_sync_start(params);
  113. std::cout << "can sync start = " << val << std::endl;
  114.  
  115. snd_pcm_close(handle);
  116.  
  117. return ;
  118. }
3.)一个简单的声音播放程序
  1. #include <iostream>
  2. #include <alsa/asoundlib.h>
  3.  
  4. int main()
  5. {
  6. long loops;
  7. int rc;
  8. int size;
  9. snd_pcm_t* handle;
  10. snd_pcm_hw_params_t* params;
  11. unsigned int val;
  12. int dir;
  13. snd_pcm_uframes_t frames;
  14. char* buffer;
  15.  
  16. if ( (rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, )) < )
  17. {
  18. std::cerr << "unable to open pcm device: " << snd_strerror(rc) << std::endl;
  19. exit();
  20. }
  21.  
  22. snd_pcm_hw_params_alloca(&params);
  23.  
  24. snd_pcm_hw_params_any(handle, params);
  25.  
  26. snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
  27.  
  28. snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
  29.  
  30. snd_pcm_hw_params_set_channels(handle, params, );
  31.  
  32. val = ;
  33.  
  34. snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
  35.  
  36. frames = ;
  37. snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
  38.  
  39. if ( (rc = snd_pcm_hw_params(handle, params)) < )
  40. {
  41. std::cerr << "unable to set hw paramseters: " << snd_strerror(rc) << std::endl;
  42. exit();
  43. }
  44.  
  45. snd_pcm_hw_params_get_period_size(params, &frames, &dir);
  46. size = frames * ;
  47. buffer = new char[size];
  48.  
  49. snd_pcm_hw_params_get_period_time(params, &val, &dir);
  50.  
  51. loops = / val;
  52.  
  53. while (loops > ) {
  54. loops--;
  55. if ( (rc = read(, buffer, size)) == )
  56. {
  57. std::cerr << "end of file on input" << std::endl;
  58. break;
  59. }
  60. else if (rc != size)
  61. std::cerr << "short read: read " << rc << " bytes" << std::endl;
  62.  
  63. if ( (rc = snd_pcm_writei(handle, buffer, frames)) == -EPIPE)
  64. {
  65. std::cerr << "underrun occurred" << std::endl;
  66. snd_pcm_prepare(handle);
  67. }
  68. else if (rc < )
  69. std::cerr << "error from writei: " << snd_strerror(rc) << std::endl;
  70. else if (rc != (int)frames)
  71. std::cerr << "short write, write " << rc << " frames" << std::endl;
  72. }
  73.  
  74. snd_pcm_drain(handle);
  75. snd_pcm_close(handle);
  76. free(buffer);
  77.  
  78. return ;
  79. }
4.)一个简单的记录声音的程序
  1. #include <iostream>
  2. #include <alsa/asoundlib.h>
  3.  
  4. int main()
  5. {
  6. long loops;
  7. int rc;
  8. int size;
  9. snd_pcm_t* handle;
  10. snd_pcm_hw_params_t* params;
  11. unsigned int val;
  12. int dir;
  13. snd_pcm_uframes_t frames;
  14. char* buffer;
  15.  
  16. if ( (rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, )) < )
  17. {
  18. std::cerr << "unable to open pcm device: " << snd_strerror(rc) << std::endl;
  19. exit();
  20. }
  21.  
  22. snd_pcm_hw_params_alloca(&params);
  23.  
  24. snd_pcm_hw_params_any(handle, params);
  25.  
  26. snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
  27.  
  28. snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
  29.  
  30. snd_pcm_hw_params_set_channels(handle, params, );
  31.  
  32. val = ;
  33. snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
  34.  
  35. if ( (rc = snd_pcm_hw_params(handle, params)) < )
  36. {
  37. std::cerr << "unable to set hw parameters: " << snd_strerror(rc) << std::endl;
  38. exit();
  39. }
  40.  
  41. snd_pcm_hw_params_get_period_size(params, &frames, &dir);
  42.  
  43. size = frames * ;
  44. buffer = new char[size];
  45.  
  46. snd_pcm_hw_params_get_period_time(params, &val, &dir);
  47.  
  48. loops = / val;
  49.  
  50. while (loops > )
  51. {
  52. loops --;
  53. rc = snd_pcm_readi(handle, buffer, frames);
  54. if (rc == -EPIPE)
  55. {
  56. std::cerr << "overrun occurred" << std::endl;
  57. snd_pcm_prepare(handle);
  58. }
  59. else if (rc < )
  60. std::cerr << "error from read: " << snd_strerror(rc) << std::endl;
  61. else if ( rc != (int)frames)
  62. std::cerr << "short read, read " << rc << " frames" << std::endl;
  63. rc = write(, buffer, size);
  64. if (rc != size)
  65. std::cerr << "short write: wrote " << rc << " bytes" << std::endl;
  66. }
  67.  
  68. snd_pcm_drain(handle);
  69. snd_pcm_close(handle);
  70. free(buffer);
  71.  
  72. return ;
  73. }

注意:编译的时候记得加上参数,g++ xxx.cpp -o xxx -lasound;如果编译时出现如下错误:alsa/asoundlib.h: No such file or directory

缺少一个库:

apt-get install libasound2-dev

OK!

 

ubuntu alsa的更多相关文章

  1. Ubuntu下声卡驱动解决方法alsa

    一.首先介绍一下什么是ALSA : Advanced Linux Sound Architecture 的简称为 ALSA ,译成中文的意思是先进的Linux声音架构(这是google翻译的):一谈到 ...

  2. Ubuntu 杂音 alsa*

    $ sudo alsactl init # 初始化 $ sudo alsactl store # 存储状态 会调的话可以 $ alsamixer

  3. ubuntu声音系统

    查看声卡:cat /proc/asound/cards 显示所有ALSA的组件:cat /proc/asound/device aplay -l ubuntu使用pulseaudio,是ALSA(先进 ...

  4. sysv-rc-conf管理Ubuntu server开机启动服务

    在RedHat中,都是使用chkconfig来管理服务的,但是在Ubuntu Server中,却有一个更好的工具,chkconfig也是可以使用的.今天来说一下sysv-rc-conf sysv-rc ...

  5. ubuntu入门

    Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音.了解发音是有意义的,您不是第一个为此困惑的人,当然,也不会是最后一个:) 大多数的美国人读 ubun ...

  6. ubuntu下编译VLC

    ubuntu下编译VLC 标签(空格分隔): ubuntu vlc 视频 编译 [TOC] 1.下载VLC源码包并解压 VLC的源码包在VLC的官网有,可以直接下载.也可以使用git来clone一个. ...

  7. ubuntu中的Wine详解

    什么是wine?(转自百度百科,具体看百科) wine,是一款优秀的Linux系统平台下的模拟器软件,用来将Windows系统下的软件在Linux系统下稳定运行,该软件更新频繁,日臻完善,可以运行许多 ...

  8. Ubuntu升级没有声音的解决方法

    自从安装U14.04LTS版本后,每次开机都会弹出update窗,以前因为网络速度慢没更新成功过,这回环境允许就尝试了下这个过程,很顺利,可更新后没声音了,找了N中方法来解决,像更改配置文件/etc/ ...

  9. Ubuntu下编译内核

    一.下载源代码和编译软件的准备 下载内核源代码:http://www.kernel.org/ 注意,点击2.6.25内核的F版,即完整版. 如果你懒得去网站点联接,运行下列命令:  代码: $cd ~ ...

随机推荐

  1. .Net MVC 自定义Action类型,XmlAction,ImageAction等

    MVC开发的时候,难免会用到XML格式数据,如果将XML数据当作字符串直接返回给前台,其实这不是真正意义上的xmL,你可以看到ContentType是text/html而非XML类型,这往往会造成前端 ...

  2. Redis PHP连接操作

    安装 在PHP程序中使用Redis,需要确保我们有Redis的PHP驱动程序和PHP安装设置在机器上.可以查看PHP教程教你如何在机器上安装PHP.现在,让我们来看看一下如何设置Redis的PHP驱动 ...

  3. 【css】关于 hr 在各浏览器中的问题

    在做页面是有时候会用到分割线 hr,但是在 ie6 和 ie7 下显示很蛋疼,本文将教你如何写出兼容各浏览器的 hr. 首页我们先了解下 hr 在各浏览器下的差异,如下表格:   正常浏览器 ie6. ...

  4. HTML(四):行级标签和块级标签

    一.行级标签 行级标签又称为内联标签,行级标签不会单独占据一行,设置宽高无效,行内内部可以容纳其他行内元素,但不可以容纳块元素,不然会出现无法预知的效果. 常见行级标签: span.strong.em ...

  5. js dom添加回车事件

    <!DOCTYPE html> <html lang="en" class="no-js"> <head> <meta ...

  6. Tornado + Celery + RabbitMQ

    声明:代码是从项目中截取的, 为进行测试 使用Celery任务队列,Celery 只是一个任务队列,需要一个broker媒介,将耗时的任务传递给Celery任务队列执行,执行完毕将结果通过broker ...

  7. ERROR:tornado上传文件过大超出范围报错

    该怎么解决呢? HTTPServer里面指定max_buffer_size就可以了 EXAMPLE # server = HTTPServer(application, max_buffer_size ...

  8. 图形界面至少要有一个顶级Swing容器

    图形界面至少要有一个顶级Swing容器 顶级Swing容器为其它Swing组件在屏幕上的绘制和处理事件提供支持 常用的顶级容器: JFrame(框架):表示主程序窗口 JDialog(对话框):每个J ...

  9. 数据抓取的艺术(三):抓取Google数据之心得

    本来是想把这部分内容放到前一篇<数据抓取的艺术(二):数据抓取程序优化>之中.但是随着任务的完成,我越来越感觉到其中深深的趣味,现总结如下: (1)时间     时间是一个与抓取规模相形而 ...

  10. LintCode #1 A + B 问题

    分析:以3 + 5为例 3的二进制为 1 1,5的二进制为 1 0 1,可以这样做:1先给这两个数加起来不考虑进位,这样得到的结果为 1 1 0,会发现与^得到的结果相同,与是先给两个数 做^运算:2 ...