# 地址(Address)
地址: 以太坊地址的长度,大小20个字节,160位,所以可以用一个`uint160`编码。地址是所有合约的基础,所有的合约都会继承地址对象,也可以随时将一个地址串,得到对应的代码进行调用。当然地址代表一个普通帐户时,就没有这么多丰富的功能啦。
## 支持的运算符
- `<=`,`<`,`==`,`!=`,`>=`和`>`
## 地址类型的成员
属性:`balance`<br/>
函数:`send()`,`call()`,`delegatecall()`,`callcode()`。
## 地址字面量
十六进制的字符串,凡是能通过地址合法性检查(address checksum test),就会被认为是地址,如`0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF`。需要注意的是39到41位长的没有通过地址合法性检查的,会提示一个警告,但会被视为普通的有理数字面量。
## `balance`
通过它能得到一个地址的余额。
```
pragma solidity ^0.4.0;
contract addressTest{
function getBalance(address addr) returns (uint){
return addr.balance;
}
}
```
我们可以把上述代码放入[remix](https://ethereum.github.io/browser-solidity)中,看看效果,参见下面的操作演示:
![address_demo](https://box.kancloud.cn/f7e0c054857ca3c86d2378a6f8eaaa66_1277x681.gif)
演示中的一个核心要点是,编译后,我们能得到当前合约的地址,并将该地址复制到输入框中,记得录入地址项时要加英文的双引号,否则会报`Error encoding arguments: SyntaxError: JSON Parse error: Expected ']'`。
## `this`
如果只是想得到当前合约的余额,其实可以这样写:
```
pragma solidity ^0.4.0;
contract addressTest{
function getBalance() returns (uint){
return this.balance;
}
}
```
原因是对于合约来说,地址代表的就是合约本身,合约对象默认继承自地址对象,所以内部有地址的属性。
## 地址的方法`send()`
用来向某个地址发送货币(货币单位是`wei`)。
```
pragma solidity ^0.4.0;
//请注意这个仅是Demo,请不要用到正式环境
contract PayTest {
//得到当前合约的余额
function getBalance() returns (uint) {
return this.balance;//0
}
//向当前合约存款
function deposit() payable returns(address addr, uint amount, bool success){
//msg.sender 全局变量,调用合约的发起方
//msg.value 全局变量,调用合约的发起方转发的货币量,以wei为单位。
//send() 执行的结果
return (msg.sender, msg.value, this.send(msg.value));
}
}
```
这个合约实现的是充值。`this.send(msg.value)`意指向合约自身发送`msg.value`量的以太币。`msg.value`是合约调用方附带的以太币。
下面是操作演示:
![address_demo_2](https://box.kancloud.cn/a39dd6005bebacf3c3bfa5b35df06e7a_1277x681.gif)
关于发送者的帐号,发送的以太币数量设置,需切换到Remix的小飞机图标的配置页。要在调用`deposit`前在`Value`输入项填入要发的以太币数量。在`getBalance`时要记得将`value`项内填的值去掉,因为`getBalance`方法,并不是`payable`的,不支持货币。
`send()`方法执行时有一些风险
1. 调用递归深度不能超1024。
1. 如果`gas`不够,执行会失败。
1. 所以使用这个方法要检查成功与否。或为保险起见,货币操作时要使用一些最佳实践。
如果执行失败,将会回撤所有交易,所以务必留意返回结果。
## `call()`,`callcode()`和`delegatecall()`
为了同一些不支持ABI协议的进行直接交互(一般的`web3.js`,`soldity`都是支持的)。可以使用`call()`函数,用来向另一个合约发送原始数据。参数支持任何类型任意数量。每个参数会按规则(规则是按ABI)打包成32字节并一一拼接到一起。
`call()`方法支持ABI协议[ABI]定义的函数选择器。如果第一个参数恰好4个字节,在这种情况下,会被认为根据ABI协议定义的函数器指定的函数签名[ABI]。所以如果你只是想发送消息体,需要避免第一个参数是4个字节。
`call`方法返回一个`bool`值,以表明执行成功还是失败。正常结束返回`true`,异常终止返回`false`。我们无法解析返回结果,因为这样我们得事前知道返回的数据的编码和数据大小(这里的潜在假设是不知道对方使用的协议格式,所以也不会知道返回的结果如何解析,有点祼协议测试的感觉)。
同样我们也可以使用`delegatecall()`,它与`call`方法的区别在于,仅仅是代码会执行,而其它方面,如(存储,余额等)都是用的当前的合约的数据。`delegatecall()`方法的目的是用来执行另一个合约中的工具库。所以开发者需要保证两个合约中的存储变量能兼容,来保证`delegatecall()`能顺利执行。
在homestead阶段之前,仅有一个受限的多样的`callcode()`方法可用,但并未提供对`msg.sender`,`msg.value`的访问权限。
上面的这三个方法`call()`,`delegatecall()`,`callcode()`都是底层的消息传递调用,最好仅在万不得已才进行使用,因为他们破坏了Solidity的类型安全。
关于`call()`函数究竟发的什么消息体,函数选择器究竟怎么用,参见[这个文章](http://me.tryblockchain.org/Solidity-call-callcode-delegatecall.html)的挖掘。
> 上述的函数都是底层的函数,使用时要异常小心。当调用一个未知的,可能是恶意的合约时,当你把控制权交给它,它可能回调回你的合约,所以要准备好在调用返回时,应对你的状态变量可能被恶意篡改的情况。
- Solidity语言
- 入门说明
- Solidity智能合约文件结构
- 智能合约源文件的基本要素概览
- 值类型
- 类型
- 布尔
- 整型
- 地址
- 字节数组
- 小数
- 字符串
- 十六进制字面量
- 枚举
- 函数
- 引用类型
- 引用类型
- 数据位置
- 数组
- 数据结构
- 杂项
- 映射
- 左值运算符
- 类型间的转换
- 类型推断
- 单位
- 货币单位
- 时间单位
- 语言内置特性
- 特殊变量及函数
- 数学和加密函数
- 地址相关
- 进阶
- 入参和出参
- 控制结构
- 函数调用
- 创建合约实例
- 表达式的执行顺序
- 赋值
- 作用范围和声明
- 异常
- 内联汇编
- 合约详解
- 合约
- 可见性或权限控制
- 访问函数
- 函数修改器
- 常状态变量
- 回退函数
- 事件
- 继承
- 接口
- 其它
- 库
- 状态变量的存储模型
- 内存变量的存局
- 调用数据的布局