2010年9月27日 星期一
2010年7月23日 星期五
call by value、address、reference
分別說明C++中 call by value , call by address , call by reference 與C的關係
參考來源 :
ofstream的參數傳虒 為什麼要加 & 運算子? / C++ / 程式設計俱樂部
裡面sflam(Raymond)大大的回覆
-----------------------------------------------------------------------------------------------------------
參考來源 :
ofstream的參數傳虒 為什麼要加 & 運算子? / C++ / 程式設計俱樂部
裡面sflam(Raymond)大大的回覆
-----------------------------------------------------------------------------------------------------------
2007/11/2 下午 10:48:47
我個人覺得 "call by X" 這個說法容易造成誤解, 我比較喜歡用 "pass by X". 因為這裡講的是參數如何傳遞, 而不是函式如何呼叫.
嚴格說起來, C 沒有 "pass by address" 這個東西. 所有的參數都是 "pass by value". 即使傳入的是個位址也是如此. 如果傳入的參數是個位址, 那接收的函式就必須是個指標, 指標所得到的是位址的值, 都是 value.
比方說:
int main()
{
int i;
func(&i);
...
}
void func(int *pi)
{
...
}
在 main() 裡:
int i
+=====+
〔i的位址〕| |
| +=====+
|
|
| 在 func() 裡, pi 得到一份 「i 位址的拷貝」...
|
| int *pi
| +=========+
+----+->〔i的位址〕 |
+=========+
結果就是, func() 裡的 pi 指向 main() 裡的 i:
i
+=====+
| |<--+
+=====+ |
| main()
~~~~~~~~~~~~|~~~~~~
| func()
pi |
+=====+ |
| *---+---+
+=====+
在 func() 裡面更改 pi 所指向的記憶體, 也就更改了 main() 裡面的 i. 如果函式要修改上一層的變數, 在 C 語言裡面唯一的方法就是傳入變數的位址, pass an address. 所傳的方式是這個位址的值, the address is pass by value.
所以 "pass by address" 可以看成是 "pass the address by value".
C++ 除了 C 的 pass by value 外, 也支援 "pass by reference" 的概念. 在概念上, reference 可以看成是一個變數的別名. 更改這個別名的內容也就更改了這個別名所代表的變數內容.
比較看看三種做法在語法上有什麼不同:
〔1: pass by value〕
int main()
{
int i;
func(i);
}
void func(int i2) { ... }
〔2: pass an address by value〕
int main()
{
int i;
func(&i);
}
void func(int *p) { ... }
〔3: pass by reference〕
int main()
{
int i;
func(i);
}
void func(int &i2) { ... }
在 〔1〕 裡, 不管 func() 裡面如何更改 i2, 都不會影響到 main() 裡的 i.
在 〔2〕 裡, func() 是透過 *p 去改變 main() 裡 i 的值.
在 〔3〕 裡, i2 是 i 的別名. func() 更改 i2 的值, main() 裡的 i 也會跟著改變.
在 C 語言裡, 只有 〔1〕 跟 〔2〕 兩種寫法. 要把 〔1〕 改成 〔2〕, 呼叫的地方跟函式的內容都要更改.
在 C++ 語言裡, 三種寫法都可以用. 單單看 main(), 〔1〕 跟 〔3〕是沒有分別的. 要把 〔1〕 改成 〔3〕, 只需把函式的參數加個 '&'.
〔1〕 跟 〔3〕 的最大分別是: 物件的拷貝. 在 〔1〕 裡, 物件會被拷貝. 〔3〕 則不會, i2 跟 i 是同樣的物件.
樓主的問題就是『物件有無拷貝』的問題. 有些物件是不能或不適合拷貝的, 比方說 ostream.
ostream 是個 C++ 物件, 它有一個對應的檔案物件. C++ 物件是個抽象的物件, 在記憶體裡. 它對應的檔案是個實在的物件, 存在磁碟裡. 這兩個物件的 states 必須要一致, 要同步才能 work. 如果這個物件被拷貝了, 那同一個檔案物件就對上了一個以上的 ostream 物件. 只要其中一個 ostream 物件更改了它的 state (比方說在函式裡輸出一些值到檔案裡, 或關閉檔案), 那其他的 ostream 的 state 就跟檔案的 state 不一致, 不同步了. 當然就會造成很大的問題.
所以像這類不適合拷貝的物件, 只能用 〔2〕 或 〔3〕 的方式來做. 用 reference 是比較方便, 因為 pointer 還要用 dereference 的語法.
其它『不能拷貝的物件』的例子還滿多的, 像 MFC 的 CWnd 及所有 CWnd 衍生的物件都是基於同樣的原因, 不能拷貝的物件.
2010年7月13日 星期二
VS2005 inline function 反組譯追蹤
開發平台: VC++ , Windows
使用行內涵式時,修飾詞inline會告知編譯器,
每當程式碼呼叫此函式時,就會產生一函式副本來取代該函式呼叫,
以便節省呼叫函式的時間。
也就是說,
程式控制權一直在main()裡面(假設在main中呼叫inline函式),
而非每次呼叫函式時便轉移控制權到該函式。
如何在vs2005平台偵錯模式中觀察這個差異?
在專案->屬性
使用行內涵式時,修飾詞inline會告知編譯器,
每當程式碼呼叫此函式時,就會產生一函式副本來取代該函式呼叫,
以便節省呼叫函式的時間。
也就是說,
程式控制權一直在main()裡面(假設在main中呼叫inline函式),
而非每次呼叫函式時便轉移控制權到該函式。
如何在vs2005平台偵錯模式中觀察這個差異?
在專案->屬性
在屬性視窗中,預設debug mode 的內嵌函式展開屬性為"預設"
要觀察行內涵式的反組譯須把偵錯模式改為release,內嵌行式展開設為"僅_inline"
避免編譯時因最佳化關係自動把函式inline起來
~觀察反組譯~

inline function 程式碼已內嵌
一般函式叫用,可以看到第4行 :0040106B call countcubeVolume1 (401140h)
程式執行至此,會call countcubeVolume1 。
2009年7月5日 星期日
使用nusoap建立web service-範例
首先 分別撰寫cliet與server端程式,放在nusoap資料夾下
server端部分程式碼撰寫原則:
server端-WSservertest.php:
其中main是自定類別,裡面就是自己寫的一些程序
接下來示範如何調用剛剛寫好的函式connectandsave
client端部分程式碼撰寫原則:
client端-WSclienttest.php :
server端部分程式碼撰寫原則:
- 撰寫欲被client調用的函式connectandsave($content)
- 引入nusoap require_once("lib/nusoap.php");
- 建立soap_server實體 new soap_server()
- 配置WSDL文件敘述 configureWSDL
- 為服務註冊register方法函式(connectandsave)
- 使用service方法執行方法並回傳值 $server->service($POST_DATA);
server端-WSservertest.php:
<?php
//定義service處理函式
function connectandsave($content)
{
$xx = main::toStore($content);
return "get \r\n" . main::$accuracy2 . "\r\n" ;
//return "get \r\n" . $content . "\r\n" ."dd";
}
date_default_timezone_set("Asia/Taipei");
require_once("lib/nusoap.php");
$server = new soap_server();// 初始化一個service物件實體
$server->soap_defencoding='UTF-8';
$server->decode_utf8=false;
$server->configureWSDL("SimpleService");// 配置 WSDL 描述,叫用時以此為類別名稱
$server->wsdl->schemaTargetNamespace = $namespace; // set namespace
// register service's WebMethod,註冊過的程序才能被訪問到
// $server->register('answerHello',array('name' => 'xsd:string'),array('return' => 'xsd:string'));
$server->register(
// method name:
'connectandsave',
// parameter list:
array('name'=>'xsd:string'),
// return value(s):
array('return'=>'xsd:string'),
// namespace:
$namespace,
// soapaction: (use default)
false/*,
// style: rpc or document
'document',
// use: encoded or literal
'encoded',
// description: documentation for the method
'Anser Hello to World '*/);
//把client端 post 過來的資料,傳給server物件的 service 方法處理。
//service 方法處理的資料會借調用相應的函式回傳給叫用端
$POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA'])
? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
$server->service($POST_DATA);
exit();
?>
其中main是自定類別,裡面就是自己寫的一些程序
接下來示範如何調用剛剛寫好的函式connectandsave
client端部分程式碼撰寫原則:
- 引入nusoap require_once("lib/nusoap.php");
- 建立soapclient()實體 new soapclient()
- 將要傳送的資料陣列化(array)
- 使用call方法叫用欲呼叫的方法call(函式名)
- 印出call完後的值;
client端-WSclienttest.php :
<?php
require_once("lib/nusoap.php");
//初始化 client 物件,是class soapclient 的一個實體
//把服務程序的 URL 地址傳遞给soapclient類別的構造函式
$client = new soapclient('http://xxxx/nusoap/WSservertest.php'); //後面利用client物件的 call 方法調用 WEB 服务的程序'GPSconnectandsave'
$myname = 'clark' ;
// $Content = '25.07433874,121.52545941,2009-05-23,17:53:56,1.2,5,2.3,2.6,8.3,xxx' ; //中原國小門口
$Content = '24.956846,121.242451,2009-05-23,17:53:56,1.2,5,2.3,2.6,8.3,xxx' ; //中原大草皮
$parameters=array('24.956846,121.242451,2000-01-01,17:53:56,1.2,5,2.3,2.6,8.3,xxx');
$str=$client->call('connectandsave',$parameters); //call('函式名',匹配的參數) 函式名為在WSservertest.php中所註冊的函式
//$str=$client->call('hello'); //客户端对象的 getError() 方法可以用来检查调用过程是否出现错误。
//如果没有错误, getError() 方法返回 false ;如果有错误, getError()方法返回错误信息。
if (!$err=$client->getError()) {
echo " return:",htmlentities($str,ENT_QUOTES); //the optional second quote_style parameter lets you define what will be done with 'single' and "double" quotes. It takes on one of three constants with the default being ENT_COMPAT: ,ENT_QUOTES Will convert both double and single quotes.
} else {
echo " error :",htmlentities($err,ENT_QUOTES);
}
//觀察request 和 response響應
echo '<p/>';
echo 'Request:';
echo '<pre>',htmlspecialchars($client->request,ENT_QUOTES),'</pre>';
echo 'Response:';
echo '<pre>',htmlspecialchars($client->response,ENT_QUOTES ),'</pre>';
?>
2009年6月29日 星期一
fsockopen穿越proxy-以台灣簡訊為例
fsocjopen 可以跟伺服器主機連線,只要知道IP、port 就好,但容易遇到的問題是,萬一讀取網頁時是靠proxy來達成的時候,那該怎麼做呢?
其實,一樣可以用fsockopen,但我們連線到proxy,在直接下指令給proxy即可
下面範例是在作專題時,使用台灣簡訊來發送客製化簡訊,欲到的proxy是中原大學的proxy.cycu.edu.tw port:3128
上面程式碼其中的211.78.23.230 是台灣簡訊的server,要注意的是
這邊要放 http://211.... 也就是絕對路徑!!
此範例由台灣簡訊API提供的範例程式作修改。
其實,一樣可以用fsockopen,但我們連線到proxy,在直接下指令給proxy即可
下面範例是在作專題時,使用台灣簡訊來發送客製化簡訊,欲到的proxy是中原大學的proxy.cycu.edu.tw port:3128
<?
$username = "xx"; // 帳號
$password = "xx"; // 密碼
$type = "now"; // 發送型態
$mobile = "0988xxxxxx"; // 電話
$message = "簡訊測試喔"; // 簡訊內容
$encoding = "big5"; // 簡訊內容編碼
$popup = ""; // 使用 POPUP 顯示
$mo = ""; // 使用雙向簡訊
$vldtime = "86400"; // 簡訊有效期限
$dlvtime = ""; // 預約時間
$MSGData = "";
$msg =
"username=".$username."&password=".$password."&type=".$type."&encoding=".$encoding."&popup=".$popup."&m
o=".$mo."&mobile=".$mobile."&message=".urlencode($message)."&vldtime=".$vldtime."&dlvtime=".$dlvtime;
$num = strlen($msg);
// 打開 API 閘道
$fp = fsockopen ("proxy.cycu.edu.tw", 3128);
// print_r($fp);
if ($fp) {
$MSGData = $MSGData."POST http://211.78.23.230/send_sms.php HTTP/1.1\r\n";
$MSGData = $MSGData."Host: api.twsms.com\r\n";
$MSGData = $MSGData."Content-Length: ".$num."\r\n";
$MSGData = $MSGData."Content-Type: application/x-www-form-urlencoded\r\n";
$MSGData = $MSGData."Connection: Close\r\n\r\n";
$MSGData = $MSGData.$msg."\r\n";
fputs ($fp, $MSGData);
// 取出回傳值
while (!feof($fp)) $Tmp[]=fgets ($fp,128);
// 關閉閘道
fclose ($fp);
// 顯示回傳值
$Respone = split(":",$Tmp[9]);
// print_r($Tmp);
$Res["Number"] = $Respone[0]; // 傳回碼
$Res["OrderID"] = $Respone[1]; // 如果傳回碼是 00 成功, 才會有 OrderID 產生
// echo '<BR>$Res["Number"] ='.$Res["Number"];
// echo '<BR>$Res["OrderID"] = '.$Res["OrderID"];
}
?>
上面程式碼其中的211.78.23.230 是台灣簡訊的server,要注意的是
這邊要放 http://211.... 也就是絕對路徑!!
此範例由台灣簡訊API提供的範例程式作修改。
2009年6月19日 星期五
PHP Excel PHPPowerPoint
兩個PHP class
PHPExcel 及 PHPPowerPoint。
分別可以很簡單地透過 PHP 讀取及寫入 Excel 2007 及 PowerPoint 2007 的檔案
用 PHP 讀寫 Excel 檔案 裡頭有讀取Excel的範例
PHPExcel 及 PHPPowerPoint。
分別可以很簡單地透過 PHP 讀取及寫入 Excel 2007 及 PowerPoint 2007 的檔案
用 PHP 讀寫 Excel 檔案 裡頭有讀取Excel的範例
2009年6月15日 星期一
2009年6月10日 星期三
在IE與FF的一些設計限制
PRB: 錯誤設定 table.innerHTML 在 Internet Explorer 中
table 的限制,在不同瀏覽器中的問題較大,需要另外處理~
IE中Table、 thead、tbody的innerHTML屬性是唯讀的!!
若用
另外要注意的是 table與 tr標籤元素,不能用innerHTML方式賦值,但.. td標籤是可以的喔!
table 的限制,在不同瀏覽器中的問題較大,需要另外處理~
IE中Table、 thead、tbody的innerHTML屬性是唯讀的!!
若用
document.getElementById("tablename").innerHTML = "XXXXX" ;
IE就會跳出「執行階段錯誤」.... ~~另外要注意的是 table與 tr標籤元素,不能用innerHTML方式賦值,但.. td標籤是可以的喔!
在IE與FF的一些設計限制(設定css屬性、註冊事件、checkbox)
在FF與其他瀏覽器(不含IE)
1.若要設定元素的class屬性,可以用 setAttribute方法來設定,如下
var inputElmt = document.createElement('input');
inputElmt.setAttribute('class', 'column');
但IE不吃這套,而吃 className 屬性名稱,如下
inputElmt.setAttribute('className', 'column');
所以 ~完整解決方法
var inputElmt = document.createElement('input');
inputElmt.setAttribute('className', 'column');
inputElmt.setAttribute('class', 'column');
寫上兩個~不需要另外辨別瀏覽器!
2.若要為其加入事件
if(document.all) //for IE
{
inputElmt.onclick = function(){ pantosetedArea(this.value) ; };
}
else inputElmt.setAttribute('onClick', "pantosetedArea(this.value)");
其中pantosetedArea(參數)是自訂函式
3.另外,若要產生預設勾選的checkbox
function createInputcheck(elmtName,elmtValue) {
elmtName = elmtName ? elmtName : '';
elmtValue = elmtValue ? elmtValue : 'yes';
var ischecked = (elmtValue=='0')? "false" : "true" ;
var inputElmt = document.createElement('input');
inputElmt.setAttribute('type', 'checkbox');
inputElmt.setAttribute('name', elmtName);
inputElmt.setAttribute('value', elmtValue);
if(elmtValue=="yes") inputElmt.setAttribute('checked', ischecked);
inputElmt.setAttribute('onClick', "checkSMS(this)")
inputElmt.setAttribute('class', 'column');
return inputElmt;
}
var sendSMSInput = createInputcheck('sSMS');
var contentTdM = document.createElement('td');
contentTdM.appendChild(sendSMSInput);
var contentTr = document.createElement('tr');
contentTr.appendChild( contentTdM );
sendSMSInput.setAttribute('checked', true);
在FF中,函式中的此行 if(elmtValue=="yes") inputElmt.setAttribute('checked', ischecked);會馬上成立,但在IE中,要為checkbox 賦值,必須等到 appendchild後才可以操作checkbox 賦值
1.若要設定元素的class屬性,可以用 setAttribute方法來設定,如下
var inputElmt = document.createElement('input');
inputElmt.setAttribute('class', 'column');
但IE不吃這套,而吃 className 屬性名稱,如下
inputElmt.setAttribute('className', 'column');
所以 ~完整解決方法
var inputElmt = document.createElement('input');
inputElmt.setAttribute('className', 'column');
inputElmt.setAttribute('class', 'column');
寫上兩個~不需要另外辨別瀏覽器!
2.若要為其加入事件
if(document.all) //for IE
{
inputElmt.onclick = function(){ pantosetedArea(this.value) ; };
}
else inputElmt.setAttribute('onClick', "pantosetedArea(this.value)");
其中pantosetedArea(參數)是自訂函式
3.另外,若要產生預設勾選的checkbox
function createInputcheck(elmtName,elmtValue) {
elmtName = elmtName ? elmtName : '';
elmtValue = elmtValue ? elmtValue : 'yes';
var ischecked = (elmtValue=='0')? "false" : "true" ;
var inputElmt = document.createElement('input');
inputElmt.setAttribute('type', 'checkbox');
inputElmt.setAttribute('name', elmtName);
inputElmt.setAttribute('value', elmtValue);
if(elmtValue=="yes") inputElmt.setAttribute('checked', ischecked);
inputElmt.setAttribute('onClick', "checkSMS(this)")
inputElmt.setAttribute('class', 'column');
return inputElmt;
}
var sendSMSInput = createInputcheck('sSMS');
var contentTdM = document.createElement('td');
contentTdM.appendChild(sendSMSInput);
var contentTr = document.createElement('tr');
contentTr.appendChild( contentTdM );
sendSMSInput.setAttribute('checked', true);
在FF中,函式中的此行 if(elmtValue=="yes") inputElmt.setAttribute('checked', ischecked);會馬上成立,但在IE中,要為checkbox 賦值,必須等到 appendchild後才可以操作checkbox 賦值
2009年6月6日 星期六
javascript 陷阱
當form裡頭有 sunmit按鈕時 如下
從外部函式觸發送出~ document.gegister.submit()
會發生 document.form.submit() is not a function 的錯誤~
解決方法就是把form裡頭的 submit弄掉就行了
從外部函式觸發送出~ document.gegister.submit()
會發生 document.form.submit() is not a function 的錯誤~
解決方法就是把form裡頭的 submit弄掉就行了
訂閱:
意見 (Atom)