2013-05-18 4 views
0

학습 테스트에서 read (2)를 사용하는 데 몇 가지 문제가 있습니다.POSIX read (2), 예기치 않은 동작

#include <stdio.h> 

int main() { 
    size_t length; 
    read(0, &length, sizeof(length)); 
    printf("input = %u\n", length); 

    return 0; 
} 

은이 코드가 표준 입출력 8 바이트 (즉 아스키 문자)을 읽는 것으로 가정 길이 변수에 저장 :

코드는 다음과 같다. 그런 다음 8 바이트의 해당 부호없는 int 값을 stdout에 인쇄합니다.

그래서 내 테스트를 해보겠습니다.이 프로그램을 리눅스 터미널에서 실행하고 'enter'하십시오. 나는 길이의 가치가 단지 10 (line feed char의 ascii 값) 일 것을 기대한다.

#include <stdio.h> 

int main() { 
    int a = 10; 
    size_t length; 
    int b = 123; 
    ssize_t n = read(0, &length, sizeof(length)); 
    printf("input = %u\n", length); 

    return 0; 
} 


$ ./test 
input = 10 

그래서, 요점은 무엇입니까 :

그러나이 테스트 (너무 많이) 실행 : 내가 기대처럼

$ ./test 
len = 4195338 

그러나이 코드 버전은 작동? 왜 임의의 미사용 변수를 추가하고 read()의 반환 값을 저장하면 동일한 입력의 결과가 달라 집니까?

N.B. read (2)는 원시 시스템 호출이고 터미널로부터 입력을 읽지 않아야한다는 것을 알고 있습니다. 이것은 단지 학습 질문입니다.

+1

어떻게 프로그램에'/ test' 공급 데이터입니다.? 프로그램에서 입력되는 내용 - 입력 데이터로 가져 오는 내용 (그리고 여전히'len = 4195338'은 아마도'input = 4195338'이어야합니다.) –

+0

@JonathanLeffler 터미널에서 프로그램을 실행 한 다음 키보드에서 엔터를 누르십시오. – eang

답변

1

sizeof(size_t) == 8 만약에 %의 LLU를 시도, 코드는 8 바이트를 읽습니다 - 사실.

일반적으로 이러한 바이트는 모두 ASCII가 아닙니다 (일부는 8 번째 비트가 설정되고 ASCII의 일부가 아닌 0x80..0xFF 범위의 값을 가짐).

그러나 문자의 변환은 없습니다. 파일에 12345678이 있으면 값은 0x3132333435363738 (또는 0x3837363534333231 일 것입니다)입니다. 변환이 필요한 경우 read(2)을 사용하지 마십시오.

printf() 형식 %zu (C99) 또는 %lu (64 비트 unsigned long 등가 size_t와 C89, 그것은 물론 unsigned long long 및 C89를 할 수 없다)이어야한다.

샘플 출력은 샘플 코드가 아닙니다. 샘플 출력은 len = ...이지만 코드는 input = ...을 생성합니다. 그래서, 당신의 문제 중 하나는 당신이 당신이 테스트하고 있다고 생각하는 것을 테스트하지 않는다는 것일 수 있습니다.

당신은 논평 :

내가 그 읽기 (2) 원시 시스템 호출과 터미널로부터 입력을 읽을 안되는 것을 알고있다.

시스템 호출은 (아마도) getchar()과 같은 기능에서 터미널에서 읽을 때 사용됩니다. 터미널에서 읽을 때이 키를 사용하는 것은 잘못된 것은 아닙니다. 문자 배열이 아닌 다른 것으로 터미널에서 읽는 것은 잘못된 것입니다.


단순히 터미널에서 프로그램을 실행 한 다음 키보드에서 Enter 키를 누르십시오.

오. 귀찮음. 네가 그렇게한다고 나는 결코 깨닫지 못했다.

글쎄, 8 바이트가 필요한 변수에 1 바이트의 데이터를 읽으면 쓰레기가 생깁니다. 변수가 안정적으로 초기화되지 않았습니다. 거기에 무슨 일이 일어나고 있는지

$ ./test 

nbytes = 1: input = 18446744073709551370 (0xFFFFFFFFFFFFFF0A) 
$ ./test 
12345678 
nbytes = 8: input = 4050765991979987505 (0x3837363534333231) 
$ ./test < /dev/null 
nbytes = 0: input = 18446744073709551615 (0xFFFFFFFFFFFFFFFF) 
$ 

당신이 볼 수 있나요 :

#include <stdio.h> 
#include <unistd.h> 

int main(void) 
{ 
    size_t length = 0xFFFFFFFFFFFFFFFF; 
    int nbytes = read(0, &length, sizeof(length)); 
    printf("nbytes = %d: input = %zu (0x%zX)\n", nbytes, length, length); 
    return 0; 
} 

두 샘플 실행 :

다음은 샘플 출력과 SSCCE (Short, Self-Contained, Correct Example)입니까? SSCCE 코드는주의를 기울이고 읽은 바이트 수를보고합니다. 읽기와 같은 작업 (항상 여기서 read()을 의미 함)에서 반환 값을 항상 확인하는 것이 중요합니다. 예상 한만큼의 데이터를 얻지 못하면 결과가 예상 한 것과 다를 수 있습니다. 'hit newline'의 값 다음에 값을 사용하는 것은 아마 '정의되지 않은 행동'일 것입니다.

(테스트 맥 OS X 10.8.3에 GCC 4.7.1와 -. 인텔 칩, 리틀 엔디안)

+0

죄송합니다.'len = ... '은 복사 - 붙여 넣기 중 오류 일뿐입니다. 나는 편집했다. 다른 정보를 가져 주셔서 감사합니다. – eang

+1

SSCCE ([짧고, 자기 포함, 올바른 예 (http://sscce.org/)])를 제공하는 것이 큰 이점이 있습니다. 왜냐하면 우리는 당신이 실제로하고있는 것을 볼 수 있기 때문입니다. 코드에 6-10 줄 (최대)을 추가합니다. 또한 프로그램에 입력 된 내용이 무엇인지에 대한 신비에 답할 수도 있습니다. –

+0

main() 관련 LOC 만 있습니다. Btw 나는 질문을 편집 할 것이다. ^^ – eang

1

를 size_t 경우 8 바이트가 당신의 printf