📜 [專欄新文章] 類 Python 的合約語言 Vyper 開發入門:與 Solidity 差異、用 Truffle 部署、ERC20 賣幣合約實做
✍️ 田少谷 Shao
📥 歡迎投稿: https://medium.com/taipei-ethereum-meetup #徵技術分享文 #使用心得 #教學文 #medium
有鑒於個人近期關注的 Uniswap 及 Curve 皆用 Vyper 實作,索性瀏覽了官方文件並嘗試一些開發工具,希望此文能減少一些讀者初嘗 Vyper 會遇到的麻煩!
Vyper and Solidity
Outline
一. Vyper 極簡介二. 與 Solidity 語法差異三. 開發、開發環境設置 1. 語法高亮 2. 本地 Vyper compiler 安裝 3. 使用 Truffle 操作 ERC20 - 安裝 Truffle - 發幣 - 寫個簡易賣幣合約四. 已知 Remix 問題 五. 結語
一. Vyper 極簡介
Vyper 是除 Solidity 外,以太坊上的另一智能合約 (Smart contract) 語言。其語法和 Python 相近,但畢竟也是寫合約的語言,邏輯差異不大,所以若熟悉 Solidity 應該不難理解用 Vyper 寫出的合約!
Vyper 主要被設計和 Solidity 的區別是安全性及可讀性,這部分會在下一段落及後方的實作中舉例說明。
二. 與 Solidity 語法差異
Vyper 與 Solidity 的差異有許多,在本段只就個人認為感受較深的三點進行說明,其他差異只進行翻譯,有興趣的讀者可以到官方文件詳細了解:https://vyper.readthedocs.io/en/latest/index.html
1. 沒有 modifier
Solidity 常見的 onlyOwner() modifier; 由於 gist 沒有 Solidity 的語法高亮,故截圖
在 Vyper 中單純用 assert 及 assert_modifiable 來進行條件檢查,兩者差別為若要檢查函數執行後的返還值,要用後者,如下圖:
Vyper 寫法
2. 沒有 Class inheritance 繼承
繼承是物件導向程式設計 (OOP) 的核心概念,但各種繼承關係有時候確實很複雜。Vyper 沒有繼承,這無疑大幅地增加了程式可讀性及安全性,以及降低審計程式碼的難度。在此提供一個例子供不熟悉 OOP 複雜之處的讀者有個概念:
source: https://consensys.github.io/smart-contract-best-practices/recommendations/#multiple-inheritance-caution
在上例中,contract A 的 fee 值 (因繼承自 contract B 和 C,故有 fee 一值) 是 5、a 值也是 5 (因繼承自 contract Final,故有 a 一值)。原因是 A 先繼承 B 再繼承 C,因此 contract A 中的 setFee() 是使用了 contract C 的 setFee(),而 a 值是由於 C(5),這代表 contract C 的 constructor (舊版本中即 function C(),函式名稱同 contract 名稱) 被傳入的值為 5。
稍微延伸一下以上概念,將 contract A 改成:contract A is C, B。如此一來,a 值還有 fee 值都會是 3,因為這次 A 先繼承 C 再繼承 B,因此最終吃到的值是 contract B 的。
以上就是 OOP 繼承的複雜之處的簡單範例說明,應該能稍微感受到爲什麼除去繼承後會大幅提高可讀性及安全性,畢竟即使是熟悉 OOP 的人有時頭腦一混亂也會開始懷疑自己寫的程式碼繼承結構是否正確 …
3. 沒有 dynamic array 動態陣列
這應該是目前 Vyper 設計中爭議最大的部分。沒有動態陣列代表在宣告陣列時需要宣告其長度,也就是說 Solidity 中的寫法 uint[], bool[] 等等,這些是不會出現在 Vyper 的。在 Vyper 中只能出現諸如:
# Vyper 的變數宣告方式為 變數名稱: 存取範圍(變數型態(若為陣列給長度))
values: uint256[10]participants: public(address[20])
可以看到上方的 uint256 及 address 兩陣列皆需要宣告長度,不能不宣告而使其動態地配置空間。
沒有動態陣列固然可以確保執行運算的範圍、次數,但一來動態陣列真的很方便、二來在 Solidity 有此功能而 Vyper 卻沒有的情況下可能會造成麻煩,詳見此一討論串:點我。
4. 沒有 inline assembly,程式碼中不會有組合語言
5. 沒有 function overloading,函式不會因傳入的參數數目不同而結果不同
6. 沒有 operator overloading,運算符號不會有不同於預設的自定義功能
7. 沒有無限迴圈,可免於 gas limit attack
8. 十進位定點數 decimal fixed point 而非二進位 (binary) 定點數,詳見:點我
三. 開發、開發環境設置
結論先講
開發 Vyper 的最佳姿勢目前個人認為是在本地裝上 Vyper compiler、用 Truffle 部署,並在撰寫時將檔名後加上 .py 就能有 Python 的語法高亮👌
1. 語法高亮 (syntax highlighting)
有語法高亮絕對是舒服地寫程式的第一步。
Remix 有 Vyper 的語法高亮,但一來個人目前不推薦使用 Remix 來撰寫 Vyper,原因詳見下方 4. 已知 Remix 問題;二來 Remix 的語法高亮其實也沒有很清楚,因此個人推薦:在本地開發,將檔名後加上 .py 就會有 Python 的語法高亮。
2. 本地 Vyper compiler 安裝
照官方說明使用 Python 的虛擬環境 virtualenv:
source: https://vyper.readthedocs.io/en/latest/installing-vyper.html#installing-vyper
簡單兩點提醒:
如果中間那行報錯但確實已經有 Python,則可能是版本問題。依照自己電腦上的版本改成相應的即可,ex: python3.6 改成 python3
進入虛擬環境後(檔案路徑前方應有 vyper-venv 的提示),使用此指令: vyper {檔案名稱}.vy,即可編譯 .vy 檔;使用完畢後輸入 deactivate 即可退出
3. 使用 Truffle 操作 ERC20
安裝 Truffle
Truffle 雖有冗餘的 migration 但也別無他法,畢竟 Remix 目前仍不完善 :(
下載流程可以照官方文件,使用 vyper-example:
source: https://github.com/truffle-box/vyper-example-box
由於我們會接上測試網 Ropsten,因此還要下載 truffle-hdwallet-provider:
source: https://github.com/trufflesuite/truffle-hdwallet-provider
接者就可以開始使用 Vyper 寫合約了!
發幣
由於 Vyper 的官方文件中已經有許多優質範例,因此本文希望來點不一樣但大家卻又很熟悉的…以 ERC20 為例(這千篇一律的主題xD):
用 Curve 的 ERC20 程式碼為範本,發一個幣(又要發…)
寫一個簡易賣幣合約
選擇這個主題一方面畢竟 ERC20 是以太坊的最大宗應用之一,二來有興趣的讀者可以透過讀 ERC20 的程式碼來熟悉 Vyper,並在看過本文的流程後對於用 Vyper+Truffle 來操作 ERC20 有完整的概念!
好的,首先複製一份 Curve 的 ERC20 程式碼(看到就順手拿來用),並複製到 Truffle 所在路徑的 contracts 資料夾中:https://github.com/curvefi/curve-contract/blob/pool_compound/vyper/ERC20.vy
由於第一點希望著重在跑一次流程,因此不改動合約的程式碼。
將 ERC20.vy 複製到 contracts 資料夾中後,到 migrations 資料夾開啟 2_deploy_contracts.js,首先將 require() 中的參數改為 ERC20.vy 的檔名 ERC20,再來依照自己喜好決定幣的名稱、代號、小數點位數及發行總量,輸入於 deployer.deploy() 中。
接著,為了和測試網 Ropsten 互動,需要將以下程式碼寫入 truffle-config.js。
第二行的 privateKeys 是帳號的私鑰。以下實作需要兩個帳號來操作,因此請從錢包匯入兩組私鑰(並非助憶詞)。
在第 13 行中 HDWalletProvider 此函式的第三個參數代表要用第幾個帳號最為預設帳號(部署合約等),第四個函數代表總共匯入幾組帳號。而第二個參數則是需要至 Infura 申請一個 project 來得到串接 Ropsten 的連結。這兩步驟並非本文重點,因此不詳細解說步驟,Google 搜尋關鍵字應該就會找到方法!
接著,就可以輸入以下指令來將代幣發佈到 Ropsten:
truffle deploy --network ropsten
有進入虛擬環境才可以編譯 .vy 檔,若忘記就會收到如下的錯誤訊息:
記得打開虛擬環境才能編譯 .vy 檔
成功後就可以在 contract address 中看到代幣發佈的位置,加入到 Metamask 中就可以看到。本文的例子是維尼代幣 Winnie the Coin, WTC ;)
contract address 便是 ERC20 的所在
Winnie the Coin, WTC
好了,到此測試網上又多了一個測試用的垃圾廢幣。
寫個簡易賣幣合約
賣幣合約中我想要簡單有兩個功能就好:付錢買幣 、結束銷售,以下就是程式碼。買幣的部分就不寫太詳細,固定價格為 0.01 Ether 可以買 500 代幣。
簡單說明幾點:
Solidity 的 constructor() 在 Vyper 中為 Python 風的 __init__():
函式的屬性(public, private, payable 等等)放在函式上方,與 Python 的修飾器位置相同
總之寫法跟 Python 很像,次方也一樣是用兩次乘法代表:**
變數前加上 self 代表是當前合約的變數/全域變數,因此非常容易與函式中的變數/區域變數做區隔
由於已經在第一行匯入了 ERC20 那份合約,因此透過將地址傳入合約當參數,就可以呼叫在該地址的合約:ERC20(self.tokenAddress) 。並且,可以將部署的合約存成一個變數 erc20 較方便
寫完合約後一樣要更改 migrations 資料夾中的 2_deploy_contracts.js 如下,將代幣所在的地址作為參數輸入。
由於先前已經部署過一次了,因此要重置才能再部署第二次,輸入以下指令:
truffle deploy --reset --network ropsten
部署成功之後就要來試著買幣啦!輸入以下來進入 console:
truffle console --network ropsten
成功進入後應該會看到 truffle(ropsten)> 的字樣。接著,首先取得部署的兩合約,並查看是否有返回合約資訊:
# ERC20 及 SellToken 是先前在 2_deploy_contracts.js 中的變數名稱,代表被部署的合約
let instance1 = await ERC20.deployed()instance1 # 印出 instance1 的資訊
let instance2 = await SellToken.deployed()instance2 # 印出 instance2 的資訊
再來,為了讓 SellToken 可以賣幣,要先用 ERC20 的合約匯幣到 SellToken 的合約。因此,輸入以下指令:
instance1.transfer(instance2.address, 10000)
# 這裡數字只要設為 > 500 就可以
接著,我們要利用第二個帳號去買幣(第一個帳號為預設帳號,因此就是代幣擁有者)。將帳號的資訊存入變數 accounts 中,再指定送出交易的帳號是第二個帳號。由於我個人匯入私鑰的順序是將第一個帳號存在 truffle-config.js 的 privateKeys[0]、第二個帳號存在 privateKeys[1],因此第二個帳號的地址就會在 accounts[1] 的位置:
let accounts = await web3.eth.getAccounts()
instance2.buyToken({from: accounts[1], value: 10000000000000000})
# value 為 10^16 是因為在 SellToken 的 buyToken 函式中買一次要 0.01 Ether, 即為 10^16 wei
然後應該就會在自己的第二個帳號中看到匯入的幣了~
最後,由於合約中結束銷售就是一個自殺 selfdestruct 函式,因此可以呼叫看看,第一個帳戶錢包中的錢應該會增加,因為第二個帳戶有付款買幣;並且,可以到 Ropsten 上瀏覽,應該能看到相關提示:
中間 contract 的右上角有 Self Destruct 的樣式
四. 已知 Remix 問題
Remix 目前有兩個版本,只有新版有 Vyper 的編譯器。在此整理目前遇到的問題,如果有人也遇到可以對照一下本處,可以省去很多自我懷疑xD
不會報錯
Remix 的編譯結果有時會是錯的、和本地端編譯出來的結果不同
舉上方的 SellToken 合約為例,將其複製到 Remix 中使用左邊的 Remote Compiler 有錯,但又不報錯 q_q (ERC20 的合約有在同檔案目錄)
左方有紅色三角形,代表編譯失敗,但沒有報錯訊息可以看…
getter function 竟然要花錢
用 Solidity 寫的合約,查詢 public 變數的值應該是不用消耗 gas 的,但不知何故查詢 Vyper 寫的合約的 public 變數卻要消耗 gas,如下圖…
可以看到中下方有 22026 gas 的消耗
Local compiler 無法使用
圖中的 Local Compiler 此選項,個人雖照官方文件執行 vyper-serve 但卻失敗,因此若有讀者成功希望能留個言不吝分享!
五. 結語
Vyper 作為一個比 Solidity 更新的合約語言,在寫程式碼的方面沒什麼問題,但相關的開發工具、學習資源等都遠不及 Solidity。
Vyper 主打的兩個特色:可讀性的部分相信看完上面的讀者應該已經有些感覺;安全性…小白如作者我倒是沒有感受到顯著的不同。況且 Solidity 已經發展許久,很多錯誤的寫法、知名的安全漏洞大家應該也很熟悉了,還有 Openzeppelin 提供安全合約寫法的範本,因此有待以後高人解說安全性是否真的是 Vyper 較好。
有興趣者可以查看 Vyper 的安全報告:點我,大意是目前 Vyper 的編譯器仍有許多問題待改進! (感謝 Chih-Cheng Liang 的提供)
本文對 Vyper 的介紹及其與 Solidity 的差異只講了個大概,欲知更詳細的介紹還是要麻煩讀者前往官方文件了:https://vyper.readthedocs.io/en/latest/index.html
最後,如果本文有任何錯誤,請不吝提出,我會盡快做修正;而如果我的文章有幫助到你,可以看看我的其他文章,歡迎一起交流 :)
田少谷 Shao - Medium
類 Python 的合約語言 Vyper 開發入門:與 Solidity 差異、用 Truffle 部署、ERC20 賣幣合約實做 was originally published in Taipei Ethereum Meetup on Medium, where people are continuing the conversation by highlighting and responding to this story.
👏 歡迎轉載分享鼓掌
同時也有5部Youtube影片,追蹤數超過7萬的網紅Mamiyoshi,也在其Youtube影片中提到,iOS14.3にアプデすると非対応機種のiPhone6s , iPhone7 , iPhone8 , iPhoneXで楽天アンリミットが使えなくなります… 今回はアップデートしてしまった方に向けてダウングレード方法を解説します! この方法を使えばデータもそのまま! ▼コマンド 【Mojave】 d...
「c# bool」的推薦目錄:
- 關於c# bool 在 Taipei Ethereum Meetup Facebook 的最佳解答
- 關於c# bool 在 Taipei Ethereum Meetup Facebook 的精選貼文
- 關於c# bool 在 國立臺灣大學 National Taiwan University Facebook 的最佳貼文
- 關於c# bool 在 Mamiyoshi Youtube 的精選貼文
- 關於c# bool 在 Mamiyoshi Youtube 的最佳貼文
- 關於c# bool 在 Mamiyoshi Youtube 的最佳貼文
- 關於c# bool 在 C# Access bool from another Form - Stack Overflow 的評價
- 關於c# bool 在 SqlServer: Translate bool ToString · Issue #14205 · dotnet/efcore 的評價
- 關於c# bool 在 Optimal way to use null conditional operators in boolean ... 的評價
c# bool 在 Taipei Ethereum Meetup Facebook 的精選貼文
📜 [專欄新文章] Reason Why You Should Use EIP1167 Proxy Contract. (With Tutorial)
✍️ Ping Chen
📥 歡迎投稿: https://medium.com/taipei-ethereum-meetup #徵技術分享文 #使用心得 #教學文 #medium
EIP1167 minimal proxy contract is a standardized, gas-efficient way to deploy a bunch of contract clones from a factory.
1. Who may consider using EIP1167
For some DApp that are creating clones of a contract for its users, a “factory pattern” is usually introduced. Users simply interact with the factory to get a copy. For example, Gnosis Multisig Wallet has a factory. So, instead of copy-and-paste the source code to Remix, compile, key in some parameters, and deploy it by yourself, you can just ask the factory to create a wallet for you since the contract code has already been on-chain.
The problem is: we need standalone contract instances for each user, but then we’ll have many copies of the same bytecode on the blockchain, which seems redundant. Take multisig wallet as an example, different multisig wallet instances have separate addresses to receive assets and store the wallet’s owners’ addresses, but they can share the same program logic by referring to the same library. We call them ‘proxy contracts’.
One of the most famous proxy contract users is Uniswap. It also has a factory pattern to create exchanges for each ERC20 tokens. Different from Gnosis Multisig, Uniswap only has one exchange instance that contains full bytecode as the program logic, and the remainders are all proxies. So, when you go to Etherscan to check out the code, you’ll see a short bytecode, which is unlikely an implementation of an exchange.
0x3660006000376110006000366000732157a7894439191e520825fe9399ab8655e0f7085af41558576110006000f3
What it does is blindly relay every incoming transaction to the reference contract 0x2157a7894439191e520825fe9399ab8655e0f708by delegatecall.
Every proxy is a 100% replica of that contract but serving for different tokens.
The length of the creation code of Uniswap exchange implementation is 12468 bytes. A proxy contract, however, has only 46 bytes, which is much more gas efficient. So, if your DApp is in a scenario of creating copies of a contract, no matter for each user, each token, or what else, you may consider using proxy contracts to save gas.
2. Why use EIP1167
According to the proposal, EIP is a “minimal proxy contract”. It is currently the known shortest(in bytecode) and lowest gas consumption overhead implementation of proxy contract. Though most ERCs are protocols or interfaces, EIP1167 is the “best practice” of a proxy contract. It uses some EVM black magic to optimize performance.
EIP1167 not only minimizes length, but it is also literally a “minimal” proxy that does nothing but proxying. It minimizes trust. Unlike other upgradable proxy contracts that rely on the honesty of their administrator (who can change the implementation), address in EIP1167 is hardcoded in bytecode and remain unchangeable.
That brings convenience to the community.
Etherscan automatically displays code for EIP1167 proxies.
When you see an EIP1167 proxy, you can definitely regard it as the contract that it points to. For instance, if Etherscan finds a contract meets the format of EIP1167, and the reference implementation’s code has been published, it will automatically use that code for the proxy contract. Unfortunately, non-standard EIP1167 proxies like Uniswap will not benefit from this kind of network effect.
3. How to upgrade a contract to EIP1167 compatible
*Please read all the steps before use, otherwise there might have problems.
A. Build a clone factory
For Vyper, there’s a function create_with_code_of(address)that creates a proxy and returns its address. For Solidity, you may find a reference implementation here.
function createClone(address target) internal returns (address result){ bytes20 targetBytes = bytes20(target); assembly { let clone := mload(0x40) mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(clone, 0x14), targetBytes) mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) result := create(0, clone, 0x37) }}
You can either deploy the implementation contract first or deploy it with the factory’s constructor. I’ll suggest the former, so you can optimize it with higher runs.
contract WalletFactory is CloneFactory { address Template = "0xc0ffee"; function createWallet() external returns (address newWallet) { newWallet = createClone(Template); }}
B. Replace constructor with initializer
When it comes to a contract, there are two kinds of code: creation code and runtime code. Runtime code is the actual business logic stored in the contract’s code slot. Creation code, on the other hand, is runtime code plus an initialization process. When you compile a solidity source code, the output bytecode you get is creation code. And the permanent bytecode you can find on the blockchain is runtime code.
For EIP1167 proxies, we say it ‘clones’ a contract. It actually clones a contract’s runtime code. But if the contract that it is cloning has a constructor, the clone is not 100% precise. So, we need to slightly modify our implementation contract. Replace the constructor with an ‘initializer’, which is part of the permanent code but can only be called once.
// constructorconstructor(address _owner) external { owner = _owner;}// initializerfunction set(address _owner) external { require(owner == address(0)); owner = _owner;}
Mind that initializer is not a constructor, so theoretically it can be called multiple times. You need to maintain the edge case by yourself. Take the code above as an example, when the contract is initialized, the owner must never be set to 0, or anyone can modify it.
C. Don’t assign value outside a function
As mentioned, a creation code contains runtime code and initialization process. A so-called “initialization process” is not only a constructor but also all the variable assignments outside a function. If an EIP1167 proxy points to a contract that assigns value outside a function, it will again have different behavior. We need to remove them.
There are two approaches to solve this problem. The first one is to turn all the variables that need to be assigned to constant. By doing so, they are no longer a variable written in the contract’s storage, but a constant value that hardcoded everywhere it is used.
bytes32 public constant symbol = "4441490000000000000000000000000000000000000000000000000000000000";uint256 public constant decimals = 18;
Second, if you really want to assign a non-constant variable while initializing, then just add it to the initializer.
mapping(address => bool) public isOwner;uint public dailyWithdrawLimit;uint public signaturesRequired;
function set(address[] _owner, uint limit, uint required) external { require(dailyWithdrawLimit == 0 && signaturesRequired == 0); dailyWithdrawLimit = limit; signaturesRequired = required; //DO SOMETHING ELSE}
Our ultimate goal is to eliminate the difference between runtime code and creation code, so EIP1167 proxy can 100% imitate its implementation.
D. Put them all together
A proxy contract pattern splits the deployment process into two. But the factory can combine two steps into one, so users won’t feel different.
contract multisigWallet { //wallet interfaces function set(address[] owners, uint required, uint limit) external;}contract walletFactory is cloneFactory { address constant template = "0xdeadbeef"; function create(address[] owners, uint required, uint limit) external returns (address) { address wallet = createClone(template); multisigWallet(wallet).set(owners, required, limit); return wallet; }}
Since both the factory and the clone/proxy has exactly the same interface, no modification is required for all the existing DApp, webpage, and tools, just enjoy the benefit of proxy contracts!
4. Drawbacks
Though proxy contract can lower the storage fee of deploying multiple clones, it will slightly increase the gas cost of each operation in the future due to the usage of delegatecall. So, if the contract is not so long(in bytes), and you expect it’ll be called millions of times, it’ll eventually be more efficient to not use EIP1167 proxies.
In addition, proxy pattern also introduces a different attack vector to the system. For EIP1167 proxies, trust is minimized since the address they point to is hardcoded in bytecode. But, if the reference contract is not permanent, some problems may happen.
You might ever hear of parity multisig wallet hack. There are multiple proxies(not EIP1167) that refer to the same implementation. However, the wallet has a self-destruct function, which empties both the storage and the code of a contract. Unfortunately, there was a bug in Parity wallet’s access control and someone accidentally gained the ownership of the original implementation. That did not directly steal assets from other parity wallets, but then the hacker deleted the original implementation, making all the remaining wallets a shell without functionality, and lock assets in it forever.
https://cointelegraph.com/news/parity-multisig-wallet-hacked-or-how-come
Conclusion
In brief, the proxy factory pattern helps you to deploy a bunch of contract clones with a considerably lower gas cost. EIP1167 defines a bytecode format standard for minimal proxy and it is supported by Etherscan.
To upgrade a contract to EIP1167 compatible, you have to remove both constructor and variable assignment outside a function. So that runtime code will contain all business logic that proxies may need.
Here’s a use case of EIP1167 proxy contract: create adapters for ERC1155 tokens to support ERC20 interface.
pelith/erc-1155-adapter
References
https://eips.ethereum.org/EIPS/eip-1167
https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7/
Donation:
pingchen.eth
0xc1F9BB72216E5ecDc97e248F65E14df1fE46600a
Reason Why You Should Use EIP1167 Proxy Contract. (With Tutorial) was originally published in Taipei Ethereum Meetup on Medium, where people are continuing the conversation by highlighting and responding to this story.
👏 歡迎轉載分享鼓掌
c# bool 在 國立臺灣大學 National Taiwan University Facebook 的最佳貼文
由片語學習C程式設計(第二版)》引導讀者進入程式設計領域
#NTU #書訊 #出版中心
《由片語學習C程式設計(第二版)》主要針對高中與大學開始接觸程式設計的初學者,及想學好程式設計的讀者所設計。書中文字敘述力求淺顯簡潔,並以大量範例、片語、學習要點、風格要點等方式,逐步引導初學者進入程式設計的領域。
二版新增C99語法,如bool類別、顯示位元數整數類別、放寬變數宣告位置、stddef的offsetof及stdlib的二分搜尋bsearch等重點介紹。以更多完整範例、相關圖示說明複雜的觀念與方法,同時強化各範例間的關聯性,讓讀者能從中反覆練習、更瞭解所學之實際應用。
本書特色以片語為主,依據慣用寫法來引導初學者進入C語言程式設計。透過「學習要點」、「風格要點」、「特殊字元」等設計,隨時提醒讀者各項學習重點,以提升學習效率。同時搭配專屬網站(https://sites.google.com/view/c-programming-2ed/home),提供各章練習題、作業、教學投影片,並隨時更新相關補充資料、程式碼等資訊。
本書作者劉邦鋒現任臺灣大學電機資訊學院美光講座教授、資訊工程系暨資訊網路與多媒體研究所教授。研究專長為平行分散式系統、演算法設計與分析。
c# bool 在 Mamiyoshi Youtube 的精選貼文
iOS14.3にアプデすると非対応機種のiPhone6s , iPhone7 , iPhone8 , iPhoneXで楽天アンリミットが使えなくなります…
今回はアップデートしてしまった方に向けてダウングレード方法を解説します!
この方法を使えばデータもそのまま!
▼コマンド
【Mojave】
defaults write com.apple.iTunes carrier-testing -bool YES
【Catalina・Big Sur】
defaults write com.apple.AMPDevicesAgent carrier-testing -bool YES
【Windows】
"C:\Program Files\iTunes\iTunes.exe" /setPrefInt carrier-testing 1
▼楽天アンリミット APN (iPhoneのSafariから開いてください)
https://drive.google.com/open?id=13HFCmW0KgB5So65-i2mqhMrW3OAP6vO7
▶楽天アンリミットのキャンペーン詳細はこちら!
https://bit.ly/3ceJq8Y
▶Macのやり方解説
https://youtu.be/r3B9rJimhRs
▶Windowsのやり方解説
https://youtu.be/IOZnPILkai0
■目次■
00:00 OP
00:21 ダウングレード方法解説
03:29 ipccファイルの作り方解説
06:33 ipccファイルの書き込み方法解説
07:41 ED
▼Apple製品動画の再生リストはこちら
https://www.youtube.com/playlist?list=PLvvYhh8sW6I28EooLdZnsnv3Fa4RB4MS8
▼サブチャンネル
https://www.youtube.com/channel/UCa9QL_VM1pmf7tmeU0EfP4Q
▼ゲームチャンネル
https://www.youtube.com/channel/UC8qfQuS4pww34aFeg5611rw
▼Twitter
https://twitter.com/mamiyoshi_
▼仕事連絡先
[email protected]
#RakutenUNLIMIT #楽天UNLIMIT #楽天アンリミット
c# bool 在 Mamiyoshi Youtube 的最佳貼文
遂にiPhone 12で楽天5Gを掴むことに成功しました!
実際にどのくらいの速度が出るのか、5Gによって使用感は変わるのか検証していきます!
▶楽天アンリミットVの詳細はこちら
https://bit.ly/3ceJq8Y
▼コマンド
【Mojave】
defaults write com.apple.iTunes carrier-testing -bool YES
【Big Sur】
defaults write com.apple.AMPDevicesAgent carrier-testing -bool YES
【Windows】
"C:\Program Files\iTunes\iTunes.exe" /setPrefInt carrier-testing 1
▼楽天アンリミット APN (iPhoneのSafariから開いてください)
https://drive.google.com/open?id=13HFCmW0KgB5So65-i2mqhMrW3OAP6vO7
▼まみよしのおすすめガジェット一覧
https://amzn.to/3ik8GhT
■目次■
00:00 OP
00:07 板橋3丁目で楽天5G検証
01:33 5Gで動画は快適に見れるようになるのか?
02:20 iPhone12に楽天アンリミットの5Gを対応させる方法を解説!
07:15 この方法のデメリット
08:03 通話・SMSの動作検証
09:18 ED
▼Apple製品動画の再生リストはこちら
https://www.youtube.com/playlist?list=PLvvYhh8sW6I28EooLdZnsnv3Fa4RB4MS8
▼サブチャンネル
https://www.youtube.com/channel/UCa9QL_VM1pmf7tmeU0EfP4Q
▼ゲームチャンネル
https://www.youtube.com/channel/UC8qfQuS4pww34aFeg5611rw
▼Twitter
https://twitter.com/mamiyoshi_
▼仕事連絡先
[email protected]
#iPhone12 #楽天モバイル5G #楽天アンリミットV
c# bool 在 Mamiyoshi Youtube 的最佳貼文
今回はiOS14にアプデした非対応機種のiPhone6s , iPhone7 , iPhone8 , iPhoneX などの端末で楽天アンリミットを使えるようにする方法を紹介します!
ipccの作り方!
▼コマンド
【Mojave】
defaults write com.apple.iTunes carrier-testing -bool YES
【Big Sur】
defaults write com.apple.AMPDevicesAgent carrier-testing -bool YES
【Windows】
"C:\Program Files\iTunes\iTunes.exe" /setPrefInt carrier-testing 1
▼楽天アンリミット APN (iPhoneのSafariから開いてください)
https://drive.google.com/open?id=13HFCmW0KgB5So65-i2mqhMrW3OAP6vO7
▶楽天アンリミットのキャンペーン詳細はこちら!
https://bit.ly/3ceJq8Y
▶無料で通信容量無制限の楽天モバイル「Rakuten UN-LIMIT」が最強すぎる!プラン詳細を徹底解説!
https://youtu.be/D0vrN1Sza5c
▶楽天アンリミットが最強だった…!実際に設定方法とiPhoneだけで使えるのかを検証!【楽天モバイル Rakuten UNLIMIT】
https://youtu.be/3VCg3uv_zF0
▶iPhoneで楽天アンリミットのeSIMを使う際の設定方法を解説!格安SIMと一緒に使えます!【楽天モバイル Rakuten UNLIMIT】
https://youtu.be/9PFgdagPMZA
▶楽天アンリミットで電話番号が不明で表示されない!? SMSが使えない際の対処方法!【楽天モバイル Rakuten UNLIMIT UN-LIMIT】
https://youtu.be/f6e5QdlzrUc
▶楽天アンリミットは無制限じゃない!? 通信制限状態でも快適に使える?【楽天モバイル Rakuten UNLIMIT UN-LIMIT】
https://youtu.be/Q2RYye0QSco
▶楽天アンリミットが進化!最強すぎるプランを徹底解説!【楽天モバイル Rakuten UNLIMIT UN-LIMIT】
https://youtu.be/0ckvUEL9UjY
■目次■
00:00 OP
00:28 iOS14版のipccの作り方解説
03:37 ipccファイルの書き込み方法解説
05:21 ED
▼Apple製品動画の再生リストはこちら
https://www.youtube.com/playlist?list=PLvvYhh8sW6I28EooLdZnsnv3Fa4RB4MS8
▼サブチャンネル
https://www.youtube.com/channel/UCa9QL_VM1pmf7tmeU0EfP4Q
▼ゲームチャンネル
https://www.youtube.com/channel/UC8qfQuS4pww34aFeg5611rw
▼Twitter
https://twitter.com/mamiyoshi_
▼仕事連絡先
[email protected]
#RakutenUNLIMIT #楽天UNLIMIT #楽天アンリミット
c# bool 在 SqlServer: Translate bool ToString · Issue #14205 · dotnet/efcore 的推薦與評價
Should the resulting string be compatible with the C# or the server-side string representation of the object? For example, a C# bool is stored ... ... <看更多>
c# bool 在 Optimal way to use null conditional operators in boolean ... 的推薦與評價
Optimal way to use null conditional operators in boolean expressions · c#. You are writing a boolean expression that might look like this: team.Category == "A ... ... <看更多>
c# bool 在 C# Access bool from another Form - Stack Overflow 的推薦與評價
... <看更多>