2016-08-01 4 views
0
#include <pthread.h> 
#include "../header/tlpi_hdr.h" 

static void * 
threadFunc(void *arg) 
{ 
    char *s = (char *) arg; 

    printf("%s", s); 

    return (void *) strlen(s); 
} 

int 
main(int argc, char *argv[]) 
{ 
    pthread_t t1; 
    void *res; 
    int s; 

    s = pthread_create(&t1, NULL, threadFunc, "Hello world\n"); 
    if (s != 0) 
     errExitEN(s, "pthread_create"); 

    printf("Message from main()\n"); 
    s = pthread_join(t1, &res); 
    if (s != 0) 
     errExitEN(s, "pthread_join"); 

    printf("Thread returned %ld\n", (long) res); 

    exit(EXIT_SUCCESS); 
} 

위의 코드는 지금 내가 공부하고있는 것일 뿐이지 만 데이터 형식의 변환에 대해서는 이해할 수 없습니다.C에서 데이터 형식 변환

threadFunc()에서 반환 유형은 void *입니다. 그러나이 함수에서 strlen(s)size_t입니다. 그러나 이것이 어떻게 (void *)으로 바뀔 수 있는지. 내 말은, 왜 안돼 (void *) &strlen(s)?

그리고 또한 main()에는 printf("Thread returned %ld\n", (long) res);가 있습니다.

변수 res(void *)이고 int 또는 long이 아닙니다. 따라서 다음과 같이 변경해야합니다.

(long) *res.

그러나 어떻게 이것을 (long) res으로 변경할 수 있습니까?

+1

* "왜 (공백 *) & strlen (s)"*은 컴파일되지도 않고 (아무리 의미가 없어도) * 실용적이라고 분명히 판명 할 수 있습니다. 짧은 대답 : 필자는 본질적으로 포인터가 아닌 값을 포인터에 넣고 "적합"할 것이라는 희망을 가지고 있습니다. 이를 수행하는 올바른 방법은 [''intptr_t'] (http://en.cppreference.com/w/c/types/integer) 값을 사용하는 것입니다. 그러나 분명히 그들은 정확성을 찾고 있지 않았습니다. – WhozCraig

+0

캐스트는 "내가 말하는대로해라. 내가하고있는 것을 안다"라고 말한다. 자신이하는 일을 모를 경우 위험합니다. 그것은 또한 "strlen()에 의해 반환 된 값을 마치'void *'처럼 처리합니다. - 값이 적당한 크기인지 확인하십시오 (일반적으로 이미 있습니다). 사용 된 기술은 합리적인 가정하에 작동하지만 거의 우아하지 않습니다. 나는 그것이 '정의되지 않은 행동'에 관해서 얇은 얼음을 밟고있는 것을 발견하는 것에 놀라지 않을 것이다. 그러나 나는 문제의 근원에 즉시 손가락을 집어 넣을 수 없다. –

+0

스레드 함수에서 임의의 값을 반환하는 방법을 묻는 중입니까? – 2501

답변

0

하지만 어떻게이에 따라 그 같은 오의 int 또는 단락이 될 수 그리고 나 strlen 수익률이 size_t는, (void *)로 변경할 수 있습니다. 내 말은, 왜 안 (void *) &strlen(s) (?)

strlen()의 반환 형식이 size_t, 일부 부호없는 정수 타입이다. 임의의 정수 값을 void*으로 전송하면 정의되지 않은 동작 (UB)이 발생합니다.

return (void *) strlen(s); // Undefined behavior 

코드 이/정적 전역 또는 할당 된 메모리에 말할 길이를 저장하고 주소를 반환 할 수있다. OP의 다른 코딩 목표를 충족시킬 수 있을지 의심 스럽습니다.

static size_t len = 0; 
len = strlen(s); 
return (void *) &len; 

strlen() 1의 반환 값)의 주소는 언어는 허용하더라도 &strlen(...) 2)로 촬영 한 수, 코드는 여전히 포인터의 수명을 고려할 필요가있다.

(긴) res로 어떻게 바꿀 수 있습니까?

호출 코드가 로 반환 된 포인터 UB을 방지하기 위해 동일한 유형을 해석하는 것이 중요하다.

void *res; 
... 
s = pthread_join(t1, &res); 
if (s != 0) { 
    errExitEN(s, "pthread_join"); 
} 
if (res != NULL) 
    size_t *len_ptr = (size_t*) res; 
    printf("Thread returned %zu\n", *len_ptr); 
    // or if long is truly needed 
    long len_as_long = (long) *len_ptr; 
    printf("Thread returned %ld\n", len_as_long); 
} 
0

여기서 strlenvoid * 포인터로 캐스트 한 후 다시 printf 호출에서 정수로 반환합니다. 포인터와 정수 사이의 변환에 관한

는 C99 표준은 void * 포인터가 uintptr_t 또는 intptr_t 정수로 변환 할 수 있으며, 다시 void * 포인터에 그 옵션 유형이 정의 된 경우 결과는 (원래 포인터와 같은 비교합니다 보장 Reference).

여기서 수행 된 변환은 다르며 작동하지 않을 수도 있지만 거의 모든 최신 컴퓨터가 내부적으로 정수로 포인터를 나타 내기 때문에 일반적으로 정수가 void * 포인터와 동일한 크기 인 한 작동합니다.

그렇다면 컴파일러가 이러한 종류의 변환을 처리하는 방법을 알고 있다면이 같은 작업을 수행 할 수 있지만 일반적으로 수행하면 안됩니다.

정수 값을 반환하는 적절한 방법은 다음과 같습니다. 정수 값에 대한 공간을 할당 한 다음 포인터를 반환합니다.

+2

"포인터는 내부적으로 정수이기 때문에 포인터와 같거나 작은 크기의 정수를 캐스팅하여 포인터와 백을 캐스팅 할 수 있습니다." - 포인터는 ** 정수가 아닙니다 **! 포인터와 정수 사이의 변환은 구현이 제한되어 있으며 표준에 의해 "작동"되는 것은 아닙니다. – Olaf

+0

@Olaf 포인터 **는 내부적으로 ** 단지 정수입니다. –

+2

@MarkusLaire 포인터가 정수형 repres와 동일하게 정의 된 표준의 인용문을 제공해주십시오. – 2501

-1

오류가 발생하기 때문에 (void *) & strlen을 반환 할 수 없습니다. 당신이하고 싶은 것은 var = strlen (s); return (void *) &var;. 그러나 함수의 끝에서 파기 될 변수에 대한 포인터를 반환하므로 포인터가 메모리의 비어 있거나 재정의 된 부분을 가리킬 수 있으므로 실제로는 올바르지 않습니다. 위치 12의 값을 얻기 때문에 pthread 함수가 수행하는 작업이 조금 이상합니다. pthread가 실행 중인지 확인하는 것 외에는 의미가 없습니다. What is size_t in C?

+0

로컬 변수의 주소를 반환하는 것은 정말 나쁜 생각입니다. 해당 주소를 역 참조하면 정의되지 않은 동작이 호출됩니다. – Olaf

+0

예, 그 말은 : "(변수의 주소를 돌려 준다) ... 파괴 될 변수에 대한 포인터를 반환했기 때문에 정확하지 않다 ..." – Alexi

+0

@Olaf 존재하지 않는 지역의 포인터 변수에는 트랩 값일 수있는 불확정 값이 있습니다. 포인터에 액세스하면 ub가 발생할 수 있습니다. – 2501