全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:2905
推到 Plurk!
推到 Facebook!

型別轉換問題

 
syao
初階會員


發表:66
回覆:63
積分:25
註冊:2005-02-02

發送簡訊給我
#1 引用回覆 回覆 發表時間:2006-10-13 18:16:07 IP:59.104.xxx.xxx 訂閱
#include <stdio.h>
#include
int main()
{

if (-1L < 1U)
printf ("True\n");
else
printf ("False\n");

if (-1L > 1UL)
printf("True\n");
else
printf("False\n");

system("pause");
return 0;

}

Conversion rules are more complicated when unsigned operands are involved. The problem is that comparisons between signed and unsigned values are machine-dependent, because they depend on the sizes of the various integer types. For example, suppose that int is 16 bits and long is 32 bits. Then -1L < 1U, because 1U, which is an unsigned int, is promoted to a signed long. But -1L > 1UL because -1L is promoted to unsigned long and thus appears to be a large positive number
我測試好像結果跟書上不同 , 是否這就是書上說的根基器有關machine-dependent
But -1L > 1UL because -1L is promoted to unsigned long and thus appears to be a large positive number
它是說-1L 會被提升到 unsigned long 而成的很大正整數 不過 -1L 不是是負數嗎??? 怎麼會提升到很大正整數
也搞不懂這樣提升如何讓-1L > 1UL ????
還有-1L < 1U 也搞不太懂書上説的意思
懂得朋友可以跟我講一下書中的意思嘛??? 這本是 The C programming Language K&R 我相信應該滿多人看過的
可以把轉換提升後二進制的情況寫給我看嗎?? 就以書上意思
-1L > 1UL
-1L < 1U
謝謝





aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#2 引用回覆 回覆 發表時間:2006-10-13 18:55:17 IP:61.229.xxx.xxx 未訂閱
suppose that int is 16 bits and long is 32 bits <<--這個假設在windows上就不成立了,因為都是 32bit
所以看不出來結果吧?
------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
syao
初階會員


發表:66
回覆:63
積分:25
註冊:2005-02-02

發送簡訊給我
#3 引用回覆 回覆 發表時間:2006-10-13 19:45:39 IP:59.104.xxx.xxx 訂閱

===================引 用 文 章===================
suppose that int is 16 bits and long is 32 bits <<--這個假設在windows上就不成立了,因為都是 32bit
所以看不出來結果吧?

to aftcast 我是想知道 書上的意思~~
書上是假設以 int 2byte long 4byte


But -1L > 1UL because -1L is promoted to unsigned long and thus appears to be a large positive number
它是說-1L 會被提升到 unsigned long 而成的很大正整數 不過 -1L 不是是負數嗎??? 怎麼會提升到很大正整數
我不懂的是-1L 是負數不是嗎???怎麼會提升到很大正整數這句話我搞不懂
那就算是提升到書上所謂很大的正整數那它怎麼如何比較它比 1UL 還要大???
1UL 不是也算是 unsigned long 嗎??
謝謝

justdo
高階會員


發表:2
回覆:359
積分:222
註冊:2004-08-17

發送簡訊給我
#4 引用回覆 回覆 發表時間:2006-10-14 01:19:53 IP:59.105.xxx.xxx 未訂閱
實際來看看-1L在記憶體中是怎麼表示的吧: 

long i = -1L;
unsigned char* p=(unsigned char*)&i;

for (int i=0; i〈sizeof(long); i)
cout << int(p[i]) << endl;
這段code在VC2005會跑出
255
255
255
255

也就是 -1L 在記憶體裡面是 0xffffffff
這個值改以 unsigned long 來看,就變成 4294967295 ,是unsigned long所能表示的最大值,所以比1大

重點在於怎麼去解釋一個值,當你用singed的角度去看的時候,會獲得-1
從unsigned的角度去看的時候,就會獲得最大值

ps: 自己把〈 換成 < ,找半天、試了半天,code還是無法正常顯示 XD

aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#5 引用回覆 回覆 發表時間:2006-10-14 01:33:30 IP:61.229.xxx.xxx 未訂閱
發現要send的時候,justdo已經回了,不過還是貼上來!

完全了解你想知道的東西了!
首先,要從資料儲存在媒體上的真實情形來看。其實 -1L 以電腦二進位來看,它是這樣子的(假設long是16bit以方便解說)
1111111111111111 (0xffff)
而正1UL當然就是
0000000000000001 (0x0001)

問題: 那麼請試想 unsigned long 的最大值是多大? 是的!也是 0xffff 也就是二進位 =
1111111111111111

我們可以發現其實一樣的資料對compiler來說有著不同的詮釋。這也是為何程式語言需要型別的關係。宣告型別就決定了資料以後的演算logic。

於是當compiler自動去type cast 的時候,它並沒有去改變實值的資料結構,只是改變了「詮釋」的logic。也就是 -1L 被改詮釋為 0xffffUL,這時候它當然比 1UL大了!

希望這樣的說明對你能有些幫助。

蕭沖 qs.xiao@gmail.com
http://aftcast.blogspot.com/
--All ideals are worthless unless implemented--


------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
syao
初階會員


發表:66
回覆:63
積分:25
註冊:2005-02-02

發送簡訊給我
#6 引用回覆 回覆 發表時間:2006-10-14 02:50:21 IP:59.104.xxx.xxx 訂閱

===================引 用 文 章===================
發現要send的時候,justdo已經回了,不過還是貼上來!

完全了解你想知道的東西了!
首先,要從資料儲存在媒體上的真實情形來看。其實 -1L 以電腦二進位來看,它是這樣子的(假設long是16bit以方便解說)
1111111111111111?? (0xffff)
而正1UL當然就是
0000000000000001???(0x0001)

問題: 那麼請試想 unsigned long 的最大值是多大? 是的!也是 0xffff 也就是二進位 =
1111111111111111

我們可以發現其實一樣的資料對compiler來說有著不同的詮釋。這也是為何程式語言需要型別的關係。宣告型別就決定了資料以後的演算logic。

於是當compiler自動去type cast 的時候,它並沒有去改變實值的資料結構,只是改變了「詮釋」的logic。也就是 -1L 被改詮釋為 0xffffUL,這時候它當然比 1UL大了!

希望這樣的說明對你能有些幫助。

蕭沖 qs.xiao@gmail.com
http://aftcast.blogspot.com/



_________________________________________________________________________________________________

你好:
改變了「詮釋」的logic 是指說沒去改變實際的值只是把存放長度擴大的意思嘛?? 就是16bit --> 32bit 去存放原來的值,但值還是不變
請問是這樣意思嘛?

謝謝


--All ideals are worthless unless implemented--
?
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#7 引用回覆 回覆 發表時間:2006-10-14 10:18:17 IP:61.229.xxx.xxx 未訂閱
你說 : "改變了「詮釋」的logic 是指說沒去改變實際的值只是把存放長度擴大的意思嘛?? 就是16bit --> 32bit 去存放原來的值,但值還是不變"

是的! 可以那麼說。只是你用
"值"這個字眼可能不夠精準。我覺得比較正確的說法是: 不改變實際的「資料結構」。為何這麼說?

在電腦的內部世界裡都是0101的二元概念。至於1111是什麼意思? 是數值? 是字元? 是多大? 這都是我們人類去定義的,以compiler的角度來說是型別來決定的。比如一樣的資料結構但賦予不同的型別宣告,則compiler會以不同的演算法(如比較大小)來處理。以你書上的二個例子來說:
For example, suppose that int is 16 bits and long is 32 bits. Then -1L < 1U, because 1U, which is an unsigned int, is promoted to a signed long. But -1L > 1UL because -1L is promoted to unsigned long and thus appears to be a large positive number

例1: 當 int 是16位元,long 是32位元時,為何 -1L < 1U ?
答: 因為long的長度大於int,所以 1U會被轉成long的型別,而因為要被比的是 -1L(有號數),所以 1U正確的講會被轉成「有號的long型別」。若以memory的情形來看是這樣的:
原本1U的二進位結構是 :
0000000000000001
被轉型別時,一般來說結構都不會改變,但當後來的型別長度比原本長時會補0,1U --> 1L
00000000000000000000000000000001
此時 -1L < 1L (轉變後的情形,二個都是有號數的型別喔)

而第二個例子,昨天我有說明: -1L 與 1UL比較,此時二者長度一樣,只是型別不同。當compiler自動的把 -1L 轉成 unisigned long 時(其實用"轉成"的說法也是不精準,它事實上是"解釋成",因為資料結構沒變),-1L的資料結構被解釋成正4294967295而非 -1 。此時是二個無號數的比較。詳細再多看一下昨天post的文章。

我想你也必需要了解所謂"有號數"在0101裡是如何表達的。以 16 bit int 這個有號數來說,也就是如何表達-32,768 至 32,767 ?
用的是補數的方法(1變0,0變1,然後再加1),比如說 2 與 -2 的資料結構關係是:
正2 : 0000000000000010
負2: 1111111111111110 (先把正2的01互換,得到1111111111111101,然後再加1,得1111111111111110)

若要更了解,可參考一些Assembly組合語言的書。
可能的話請盡量的推敲我畫線的那句話的意義…

很求堪解的你很不錯喔 : )

蕭沖 qs.xiao@gmail.com
http://aftcast.blogspot.com/
--All ideals are worthless unless implemented--

------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
syao
初階會員


發表:66
回覆:63
積分:25
註冊:2005-02-02

發送簡訊給我
#8 引用回覆 回覆 發表時間:2006-10-14 11:50:26 IP:59.104.xxx.xxx 訂閱
to aftcast
謝謝你詳盡解說

關於你blog 中的以C語言觀點理解C 的this指標

#include
#include
#include
typedef
struct StudentInfo
{
char *mName;
int mAgeInAc;
int mAgeInTw;
void (*mpCalc)(struct StudentInfo *self);
int (*mpGetTwAge)(struct StudentInfo *slef);
void (*mCopy)(struct StudentInfo *slef,
struct StudentInfo src);
}STI;
/* 私人的方法 */
void ac_to_tw(STI *self)
{
self->mAgeInTw = self->mAgeInAc - 1911;
}
/*公開的方法*/
int get_tw_age(STI *self)
{
self->mpCalc(self);
return self->mAgeInTw;
}
/*公開的方法*/
void copy(STI *self, STI src)
{
*self = src;
}
/*建構子*/
STI create_sti_object(void)
{
STI object;
object.mName = 0;
object.mpCalc = ac_to_tw;
object.mpGetTwAge = get_tw_age;
object.mCopy = copy;
return object;
}
/*動態建構子*/
STI *p_create_sti_object(void)
{
STI *p_object = (STI *) calloc(1,sizeof(STI));
p_object->mName = 0;
p_object->mpCalc = ac_to_tw;
p_object->mpGetTwAge = get_tw_age;
p_object->mCopy = copy;
return p_object;
}
/*動態解構子*/
void destroy_sti_object(STI *self)
{
free(self);
}
#pragma argsused
int main(int argc, char* argv[])
{
int my_tw_age;
STI student_info;
STI *p_student_info;
STI my_info;
STI babe_info;
STI copy_info;
/*沒有建構式的建立法*/
student_info.mName = "蕭一世";
student_info.mAgeInAc = 1951;
student_info.mpCalc = ac_to_tw;
student_info.mpCalc(&student_info);
printf("%s 民國%d年生\n",student_info.mName,student_info.mAgeInTw);
/*使用動態建構方式,且直接呼叫私人方法*/
p_student_info = p_create_sti_object();
p_student_info->mName = "蕭二世";
p_student_info->mAgeInAc = 1961;
p_student_info->mpCalc(p_student_info);
printf("%s 民國%d年生\n",p_student_info->mName,p_student_info->mAgeInTw);
destroy_sti_object(p_student_info);
/*使用建構子,且呼叫公開方法取回值,Instance1 */
my_info = create_sti_object();
my_info.mName = "蕭沖";
my_info.mAgeInAc = 1971;
my_tw_age = my_info.mpGetTwAge(&my_info);
printf("%s 民國%d年生\n",my_info.mName,my_tw_age);
/*使用建構子,且呼叫公開方法取回值,Instance2A */
babe_info = create_sti_object();
babe_info.mName = "寶貝";
babe_info.mAgeInAc = 1976;
my_tw_age = babe_info.mpGetTwAge(&babe_info);
printf("%s 民國%d年生\n",babe_info.mName,my_tw_age);
/*使用拷備函式,Instance2B */
copy_info = create_sti_object();
copy_info.mCopy(& copy_info, babe_info);
strcat(copy_info.mName, "拷備");
copy_info.mAgeInAc = copy_info.mAgeInAc 7;
my_tw_age = copy_info.mpGetTwAge(& copy_info);
printf("%s 民國%d年生\n",copy_info.mName,my_tw_age);
system("pause");
return 0;
}
我在gcc & dev-c 編譯可以跑出結果但之後好像會發生記憶體錯誤訊息 , 下面訊息是我在gcc 下編譯後執行結果出現程式記憶體區段錯誤 (core dumped)

Cetus:~$ ./class
蕭一世 民國40年生
蕭二世 民國50年生
蕭沖 民國60年生
寶貝 民國65年生
程式記憶體區段錯誤 (core dumped)

謝謝

syao
初階會員


發表:66
回覆:63
積分:25
註冊:2005-02-02

發送簡訊給我
#9 引用回覆 回覆 發表時間:2006-10-14 14:46:53 IP:59.104.xxx.xxx 訂閱

===================引 用 文 章===================
實際來看看-1L在記憶體中是怎麼表示的吧:?

?long i = -1L;
?unsigned char* p=(unsigned char*)&i;

?for (int i=0; i〈sizeof(long); i)
??cout << int(p[i]) << endl;
這段code在VC2005會跑出
255
255
255
255



也就是 -1L 在記憶體裡面是 0xffffffff
這個值改以 unsigned long 來看,就變成 4294967295 ,是unsigned long所能表示的最大值,所以比1大

重點在於怎麼去解釋一個值,當你用singed的角度去看的時候,會獲得-1
從unsigned的角度去看的時候,就會獲得最大值

ps: 自己把〈 換成 <!--,找半天、試了半天,code還是無法正常顯示? XD<-->
__________________________________________________________________________________________

long i = -1L;
char* p=(char*)&i;
int j;
for (j = 0; j < sizeof(long); j)
printf("%d\n",(int)(p[j]));
________________________________________________________________________


to justdo
unsigned char *p指標
我改成 char *p 指標
-1
-1
-1
-1
並非
255
255
255
255

-1L 在記憶體裡面是 0xffffffff
還是我觀念上搞錯了 想請問一下這邊 char * 跟用 unsigned char * 指標抓取的資料有何不同???
我改成char *這樣印出來是
1. p[i ] ; 用 unsigned char * 跟用 char * 指標都是一次抓取 8 bit?
2 . 是因為 -1 在 char 下看1111 1111 char 是 signed 所以看成 -1 而 unsigned char 下看 1111 1111 255 嗎??
3. p 指向 long i ... 再用unsigned char * 或是 char * 抓取8bit 長度的值 ... 我不懂是同樣 char * 跟 unsigned char * 都是抓取 8bit 長度 那為什麼 unsigned char * 可以把值看成 255 .... 而 char * 看成 -1 .... 指標不是只是抓取長度~~ 還是在printf 或是 cout 時候會查看指標是 unsigned char * 還是 char * 在進行輸出??
4 . 為何要在(int) 轉型在輸出
5. long i 可以用 float * 或是 double * 去指向 i 嗎??? 還是 整數型態必須只能由整數型指標去指向 ~~
如果這樣指向 那在假設 float 佔 2byte 跟 double 4byte
float * = (float *) & i; // 這樣也是對i 抓取16bit 長度值嗎??? 還是一樣的疑問這時候輸出值會是以 float 型態去計算後輸出嗎??
謝謝

aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#10 引用回覆 回覆 發表時間:2006-10-14 15:28:07 IP:61.229.xxx.xxx 未訂閱
謝謝你提供了一個bug report!   : -)

問題出現在:
strcat(copy_info.mName, "拷備"); //這句話有問題,雖然bcb上run一切沒問題,但改至 vc6 一樣有你說的問題。
請修正此行為
copy_info.mName = "寶貝拷備";

原因是我從頭至尾並未使用動態配置記憶體的方式來處理 copy_info.mName 欄裡的 char * 指標。而是以靜態的指定。在靜態的記憶空間裡一開始僅配"寶貝"四個byte,而後來試圖要在它的後面加入拷備這4個byte就可能會產生access violation的情形。本來是為了要演示確實有copy過來並以copy的值來變化的…

------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#11 引用回覆 回覆 發表時間:2006-10-14 15:43:17 IP:61.229.xxx.xxx 未訂閱
我想你還是沒有把我post給你的那段有畫線的部份仔細的徹底了解!  再重看思考幾次吧!

>>1. p[i ] ; 用 unsigned char * 跟用 char * 指標都是一次抓取 8 bit?
YES

>>2 . 是因為 -1 在 char 下看1111 1111??? char 是 signed 所以看成 -1?? 而 unsigned char? 下看 1111 1111? 255?? 嗎?????
YES

>>3.? p 指向? long i? ... 再用unsigned char * 或是 char * 抓取8bit 長度的值 ... 我不懂是同樣 char * 跟 unsigned char * 都是抓取 8bit 長度 那為什麼 unsigned? char * 可以把值看成 255? .... 而 char * 看成 -1 ....? 指標不是只是抓取長度~~ 還是在printf 或是 cout 時候會查看指標是? unsigned char * 還是 char * 在進行輸出??
YES

>>4 . 為何要在(int) 轉型在輸出
因為若不轉成int 型別,那麼同樣的"結構" 1111 1111,又會被解釋成"字元",於是會印出字而非數值。

所有問題的關鍵都是
在電腦的內部世界裡都是0101的二元概念。至於1111是什麼意思? 是數值? 是字元? 是多大? 這都是我們人類去定義的,以compiler的角度來說是型別來決定的。比如一樣的資料結構但賦予不同的型別宣告,則compiler會以不同的演算法(如比較大小)來處理

1111 11111的結構對compiler來說可能是 字元,若你宣告它是 char,也可能是正數,也可能是負數當你宣告signed。

型別決定該資料的演算法,而演算法決定了大小的比較,print,各式各樣的function。for example: "1" "2" = "12"; 1 2 =3; 有什麼不同? 因為型別不同導至演算法不同!

------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
系統時間:2024-05-10 8:38:17
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!