2011-11-10 3 views
6

나는이처럼 보이는 메모리에 문자열을 표현하는 구조를 가지고 :C의 printf와 문자열의 정밀도를 지정하기위한 size_t로 사용

typedef struct { 
    size_t l; 
    char *s; 
} str_t; 
내가이 size_t를 사용하여 믿고

숯불 문자열의 길이를 지정하는 의미가 있습니다를 . printf("%.*s\n", str.l, str.s)을 사용하여이 문자열을 인쇄하고 싶습니다. 그러나 * 정밀도는 size_t이 아니라 int 인수를 필요로합니다. 나는 이것에 관련된 어떤 것을 찾을 수 없었다. 이 구조를 올바르게 사용할 수 있습니까? int에 캐스트하지 않고 printf()을 호출합니까?

+0

당신은'char *'을 null로 끝내려하지 않습니까? null로 끝나면 길이에 대한 정밀도를 설정하면 무엇을 얻을 수 있는지 알 수 없습니다. 그 외에도, 여러분의 선택은 다음과 같다 :'size_t'를'int'로 변환하거나 변경하고 부정적인 것으로 허용하지 마십시오. –

+2

@EvanTeran 문자열은 실제로 더 큰 버퍼 내의 조각을 가리키고 있으므로 'null'문자가 더 어딘가에 있습니다. 'int'의 크기는 문자열이 일반적으로 최대 수백 바이트이기 때문에 문제가되지 않습니다. 나에게 좌절감을 느끼는 것은 'size_t'가이 목적에 잘 어울리지 만, C99는 'size_t'인수를 허용하는 특수 정밀도 수정자를 정의하지 않는다는 것입니다. –

답변

3

당신은 매크로

#define STR2(STR) (int const){ (STR).l }, (char const*const){ (STR).s } 

을 다음 printf("%.*s\n", STR2(str))로 사용할 수 있습니다.

이것은 STR을 두 번 평가하므로주의해야하며 부작용은 있지만 이미 알고있을 것입니다.

편집 : 이러한 암시 적 변환 것을

것은 내가 사용하고 복합 초기화 등. 일이 잘못되면 컴파일러가 명시 적 캐스트보다 경고 할 수있는 기회가 더 많습니다. STR이 포인터 필드 .l을 가지고 있으며, 당신은 단지 int에 깁스를 넣어 줄 경우

예컨대

는, 모든 컴파일러 행복하게 int에 그 포인터를 변환합니다. .s 필드와 비슷합니다. 실제로는 char* 또는 호환 가능한 항목과 일치해야합니다. 그렇지 않으면 경고 또는 오류가 표시됩니다.

+0

여전히 캐스트입니다.하지만 모든 단계에서 캐스팅하는 것보다 낫습니다. 정확히 궁금한 점은, 복합 이니셜 라이저가 명시 적 캐스트와 다른 점은 무엇입니까? GCC의 문서에는 "스칼라 유형과 공용체 유형에 대한 복합 리터럴도 허용되지만 복합 리터럴은 형 변환과 동일합니다." (http://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html) –

+0

@LuciStanescu, 내가 말했듯이 묵시적인 변환은 아닙니다. 모든 형 변환은 변환이지만 모든 변환이 형 변환이 아닙니다. 차이점은 정수형이 아닌 포인터 인'.l' 필드가있는''STR ''을 전달하면됩니다. 만약 그것이 캐스트가된다면 모든 컴파일러는 행복하게 변환 할 것입니다. 변환시 대부분의 컴파일러가 경고합니다. BTW는'.s' 필드에 대해서도 마찬가지이며 내 게시물을 편집 할 것입니다. –

+0

사실, GCC의 매뉴얼에 스칼라 유형의 경우 복합 초기화 프로그램이 캐스트와 동등하지만 non-interger 유형이 전달되면 불만을 제기한다고 언급되어 있습니다. –

5
printf("%.*s\n", (int)str.l, str.s) 
//    ^^^^^ use a type cast 

편집

OK, 나는 질문을 제대로 읽어 보지 않았다. 타입 캐스트를 사용하고 싶지는 않지만,이 경우에는 힘들다고 생각합니다.

어느 쪽이든 또는 단순히이 보장이를 size_t가 int 형이라고하지, 또는가 INT 내에서 표현 될 수 있다는 것을

fwrite(str.s, str.l, 1, stdout); 
printf("\n"); 
+1

'fwrite'제안에 +1. 나는'fwrite (str.s, 1, str.l, stdout)'을 사용하고 반환 값을 검사하여 실제 얼마나 많은 문자가 실제로 쓰여 졌는지 확인합니다. – Nemo

+0

필자가 준'printf()'예제는 실제로 예제 일 뿐이므로 size_t를 사용하여 정밀도를 지정하는 것이 목표입니다. 왜 내가'fwrite' 제안을 좋아하지 않는지 궁금하다면 : 일단 복잡한 상수 문자열, 여러개의 str_t 문자열, 숫자를 가지기 시작하고 메시지 작성을 위해'snprintf'를 사용하게되면, 포맷팅을 사용하지 않도록 너무 성가 시게됩니다. 기능. 그래서 나는 당신의 대답에서 "힘든"제안으로 붙어 있다고 믿는다 :-). 그러나 환호! –

+0

@nemo : 나는 생각했다.하지만 짧은 버전의 반환 횟수> 0을 처리해야한다. 반면에 내 버전에서는 반환 값이 1 (성공) 또는 0 (실패)이다. 내 PC (Mac OS X)의'fwrite()'에있는 문서에 따르면 어쨌든 쓰기 오류에 대해서만 짧은 계산을 할 수 있으므로 그 시점에서 무엇이든 상관없이 중단하고 싶을 것입니다. – JeremyP

1

에 fwrite 사용합니다. size_t의 구현이 대용량 메모리 영역 (MAX_INT 값 이상)을 처리하기 위해 활용되어야 할 것이라는 우려와 더불어 int의 정확한 크기를 정의하지 않는 것은 C의 유산의 일부입니다.

size_t와 관련하여 가장 일반적인 오류는 unsigned int와 동일하다고 가정하는 것입니다. 이러한 오래된 버그는 흔한 일이며, 개인적인 경험을 통해이 가정을 취소해야하므로 32 비트에서 64 비트 아키텍처로의 이식을 어렵게 만듭니다.

기껏해야 캐스트를 사용할 수 있습니다. 정말로 캐스트를 없애고 싶다면 size_t의 사용을 버릴 수도 있습니다.

+1

실제로'size_t '는 결코'int'와 같지 않을 것이라는 보장이 있습니다; 그것은 'unsigned int'와 동일 할 수도 있습니다. (부호없는 (signed) 것이어야하며, 그 크기는'int'의 크기와 같을 수도 있고 같지 않을 수도 있습니다.) –

관련 문제