2011-07-31 83 views
2

我正在從書中調試程序。該程序似乎工作,但我不明白下面我評論的一條線。爲什麼這個投射無效指針有效?

#include <pthread.h> 
#include <stdio.h> 
/* Compute successive prime numbers (very inefficiently). Return the 
Nth prime number, where N is the value pointed to by *ARG. */ 
void* compute_prime (void* arg) 
{ 
int candidate = 2; 
int n = *((int*) arg); 
while (1) { 
int factor; 
int is_prime = 1; 
/* Test primality by successive division. */ 
for (factor = 2; factor < candidate; ++factor) 
if (candidate % factor == 0) { 
is_prime = 0; 
break; 
} 
/* Is this the prime number we’re looking for? */ 
if (is_prime) { 
if (--n == 0) 
/* Return the desired prime number as the thread return value. */ 
return (void*) candidate; // why is this casting valid? (candidate is not even a pointer) 
} 
++candidate; 

} 
return NULL; 
} 
int main() 
{ 
pthread_t thread; 
int which_prime = 5000; 
int prime; 
/* Start the computing thread, up to the 5,000th prime number. */ 
pthread_create (&thread, NULL, &compute_prime, &which_prime); 
/* Do some other work here... */ 
/* Wait for the prime number thread to complete, and get the result. */ 
pthread_join (thread, (void*) &prime); 
/* Print the largest prime it computed. */ 
printf(「The %dth prime number is %d.\n」, which_prime, prime); 
return 0; 
} 

回答

6

這是無效的。如果sizeof(int) == sizeof(void *)發生在許多系統上,它就會正常工作。

A void *只能保證能夠保存指向數據對象的指針。

這是關於這個問題的C FAQ

整數如何轉換爲指針和從指針轉換? 我可以暫時將一個整數填入指針,反之亦然?

指針到整數和整數到指針轉換是 實現定義(參見問題11.33),並且不再有 的指針可以被轉換爲整數任何保證和背部, 無變化

強制指針爲整數或整數爲指針,從來 是好的做法

+0

我會返回這本書:)這確實是一個黑客,雖然是一個常見的(指針中存儲值,取決於相同類型的寬度)。 – nielsj

+0

POSIX似乎支持這種黑客攻擊:例如'SIG_IGN'。 –

+0

@Joseph Quinsey我知道;我也讀了R ..的答案,我同意。儘管如此,親自使用太難看了。 – cnicutar

1

你所說的「有效」是什麼意思?

你明確地要求轉換,而語言或編譯器不會阻止你。是否是有用是完全不同的問題。事實上,正如你所說,candidate不是一個指針,它並不指向任何有用的東西。返回值的接收者必須知道如何處理它(例如,將其重新轉換回int,但不能保證能夠讓您恢復原始值)。

如果您從不需要該值,則可能只需返回0。簡單地說,pthread_create預期類型爲void*(*)(void*)的函數指針作爲參數,所以您的函數必須返回void*。如果你不需要它,你可以忽略它並返回任何舊值。

(在其他情況下,你的線程函數可能選擇到malloc()一些內存,以結果數據填充它,並返回一個指向該地址,這就是爲什麼void*在某種意義上是「最一般的」返回類型爲C功能需要儘可能靈活而不知道將如何使用)

+0

如果函數結果無論如何都被丟棄,它可能會返回NULL,這可能比無效指針更安全。我認爲它應該返回一個整數,但這確實是一個黑客。 –

+0

@Rudy:是的,我知道,返回值實際上是存儲在'pthread_join'中的。乾淨的解決方案是將返回值存儲在作爲參數傳遞給函數的預先分配的內存區域中。 –

+0

這也是我的想法。不管你怎麼做,都很難做到這一點。 –

1

雖然其他人是正確的C離開這個演員的結果實現定義,您的代碼(使用pthreads)依賴於POSIX,它需要一個內存模型,編譯器不得不停止破壞你正在做的事情。同樣,所有真實世界的POSIX實現都是ILP32或LP64,這意味着任何值int都適合指針。

雖然「醜陋」從正規的角度來看,使用int - 到 - void *與線程參數或返回值投射傳遞小整數數據通常是兩所害,另一個選擇是在一個線程和freemalloc(sizeof(int))另一方面,這不僅從根本上增加了顯着的成本,而且對於僅在分配線程和釋放線程相同的情況下才調整的一些分配器而言,在病態上可能是不利的。

的一種方式,你可以同時避免外邪:如果線程的創建者將會堅持了一段時間,並最終調用pthread_join,你可以一個指針通過新的線程數據對象的創建者的堆棧或內存,否則由創建者擁有。新線程可以在結束之前將其結果寫入該位置。