2011-11-10 41 views
6

Tôi có một cấu trúc để đại diện cho chuỗi trong bộ nhớ tìm kiếm như thế này:Sử dụng size_t để xác định độ chính xác của một chuỗi trong printf C

typedef struct { 
    size_t l; 
    char *s; 
} str_t; 

Tôi tin rằng sử dụng size_t làm cho tinh thần để xác định độ dài của một chuỗi char . Tôi cũng muốn in chuỗi này bằng cách sử dụng printf("%.*s\n", str.l, str.s). Tuy nhiên, độ chính xác * mong đợi đối số int, không phải là size_t. Tôi đã không thể tìm thấy bất cứ điều gì có liên quan về điều này. Có cách nào để sử dụng cấu trúc này một cách chính xác, mà không cần truyền tới int trong cuộc gọi printf()?

+0

bạn không có kế hoạch vô hiệu hóa 'char *'? Nếu nó không kết thúc, tôi không thấy những gì thiết lập độ chính xác cho chiều dài sẽ giúp bạn có được ở nơi đầu tiên. Ngoài ra, tôi nghĩ rằng các lựa chọn của bạn là: cast hoặc thay đổi 'size_t' thành' int' và không bao giờ cho phép nó là tiêu cực. –

+2

@EvanTeran Các chuỗi thực sự trỏ tới các phần trong bộ đệm lớn hơn, do đó ký tự 'null' ở đâu đó xa hơn. Kích thước của một 'int' không phải là một vấn đề, vì các chuỗi thường là một vài trăm byte. Điều làm tôi thất vọng là mặc dù 'size_t' sẽ phù hợp với mục đích này một cách độc đáo, C99 không định nghĩa một công cụ sửa đổi độ chính xác đặc biệt chấp nhận một đối số' size_t'. –

Trả lời

3

Bạn có thể làm một macro

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

và sau đó sử dụng điều này như printf("%.*s\n", STR2(str)).

Hãy coi chừng rằng điều này đánh giá STR hai lần, vì vậy hãy cẩn thận với các tác dụng phụ, nhưng bạn có thể đã biết điều đó.

Edit:

Tôi đang sử dụng initializers hợp chất như rằng đây là những chuyển đổi tiềm ẩn. Nếu mọi thứ xảy ra sai thì có nhiều cơ hội mà trình biên dịch sẽ cảnh báo bạn hơn với một diễn viên rõ ràng.

ví dụ nếu STR có một trường .l đó là một con trỏ và bạn chỉ muốn đặt một dàn diễn viên để int, tất cả các trình biên dịch sẽ hạnh phúc chuyển đổi con trỏ đến int. Tương tự cho trường .s, điều này thực sự phải tương ứng với một char* hoặc một cái gì đó tương thích, nếu không bạn sẽ thấy cảnh báo hoặc lỗi.

+0

Vẫn là một diễn viên, nhưng nó trông tốt hơn so với đúc ở mỗi bước. Chỉ cần tự hỏi, làm thế nào chính xác là hợp chất khởi tạo khác với một diễn viên rõ ràng? Các tài liệu của GCC đề cập rằng: "Các chữ cái hợp chất cho các loại vô hướng và kiểu công đoàn cũng được cho phép, nhưng sau đó chữ hợp chất tương đương với một dàn diễn viên." (http://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html) –

+0

@LuciStanescu, không phải là một diễn viên, như tôi đã nói, một chuyển đổi tiềm ẩn. Tất cả các phôi là chuyển đổi nhưng không phải tất cả các chuyển đổi đều là phôi. Sự khác biệt sẽ là nếu bạn truyền vào một '" STR "' có một trường '.l' sẽ là một con trỏ chứ không phải là một kiểu số nguyên. Nếu nó là một diễn viên, tất cả các trình biên dịch sẽ vui vẻ chuyển đổi. Đối với một chuyển đổi, hầu hết các trình biên dịch sẽ cảnh báo bạn. BTW cũng đúng với trường '.s', tôi sẽ sửa bài viết của mình. –

+0

Thật vậy, mặc dù hướng dẫn của GCC đề cập rằng đối với các loại vô hướng, bộ khởi tạo hợp chất tương đương với phép đúc, nó sẽ khiếu nại nếu một kiểu không liên kết được truyền đi. –

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

Sửa

OK, tôi đã không đọc những câu hỏi đúng. Bạn không muốn sử dụng một loại cast, nhưng tôi nghĩ, trong trường hợp này: khó khăn.

Hoặc đó hoặc chỉ đơn giản là sử dụng fwrite

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

+1 cho đề xuất 'fwrite'. Mặc dù tôi có lẽ sẽ đi với 'fwrite (str.s, 1, str.l, stdout)' và kiểm tra giá trị trả về để xem có bao nhiêu ký tự được viết thành công. – Nemo

+0

Ví dụ 'printf()' gọi tôi đã thực sự chỉ là một ví dụ và câu hỏi xác định rõ ràng rằng mục tiêu là sử dụng size_t để chỉ định độ chính xác. Nếu bạn băn khoăn tại sao tôi không thích gợi ý 'fwrite': khi bạn bắt đầu có nhiều chuỗi liên tục phức tạp, nhiều chuỗi str_t, số và sử dụng' snprintf' để xây dựng thư, nó quá khó chịu khi không sử dụng định dạng chức năng. Vì vậy, tôi tin rằng tôi đang mắc kẹt với các "khó khăn" gợi ý từ câu trả lời của bạn :-). Nhưng cổ vũ! –

+0

@ nemo: Tôi nghĩ về điều đó nhưng sau đó bạn phải đối phó với một số trả về ngắn> 0 trong khi với phiên bản của tôi, giá trị trả lại là 1 (thành công) hoặc 0 (lỗi). Theo các tài liệu trên 'fwrite()' trên máy tính của tôi (Mac OS X), bạn chỉ nhận được một số đếm ngắn trên một lỗi ghi anyway, vì vậy bạn có thể muốn dừng lại, không có vấn đề gì tại thời điểm đó. – JeremyP

1

Không có đảm bảo rằng size_t là một int, hoặc nó có thể được biểu diễn trong một int. Nó chỉ là một phần của di sản của C trong việc không xác định kích thước chính xác của một int, cùng với những lo ngại rằng việc thực hiện size_t có thể cần được tận dụng để giải quyết các vùng bộ nhớ lớn (những vùng có nhiều hơn MAX_INT giá trị trong chúng).

Lỗi phổ biến nhất liên quan đến size_t là giả sử rằng nó tương đương với int không dấu. Các lỗi cũ như vậy là phổ biến, và từ kinh nghiệm cá nhân, nó làm cho việc chuyển từ kiến ​​trúc 32 bit thành kiến ​​trúc 64 bit trở thành một nỗi đau, vì bạn cần phải hoàn tác giả định này.

Tốt nhất, bạn có thể sử dụng dàn diễn viên. Nếu bạn thực sự muốn loại bỏ các diễn viên, bạn có thể loại bỏ việc sử dụng size_t.

+1

Trên thực tế, có một đảm bảo rằng 'size_t' sẽ không bao giờ tương đương với' int'; nó có thể, tuy nhiên, tương đương với 'unsigned int'. (Nó phải được unsigned, kích thước của nó có thể hoặc có thể không giống như kích thước của 'int'.) –

Các vấn đề liên quan