Làm thế nào để in uint64_t? Thất bại với: dấu vết giả mạo '%' theo định dạng


133

Tôi đã viết một mã kiểm tra rất đơn giản của printf uint64_t:

#include <inttypes.h>
#include <stdio.h>

int main()
{
  uint64_t ui64 = 90;
  printf("test uint64_t : %" PRIu64 "\n", ui64);
  return 0;
}

Tôi sử dụng Ubuntu 11.10 (64 bit) và gcc phiên bản 4.6.1 để biên dịch nó, nhưng không thành công:

main.cpp: In function int main()’:
main.cpp:9:30: error: expected ‘)’ before PRIu64
main.cpp:9:47: warning: spurious trailing ‘%’ in format [-Wformat]

1
Có vẻ như bạn đang biên dịch mã C thành C ++, đó là lỗi của bạn. Nếu bạn đổi tên tệp của mình thành main.cvà biên dịch nó với gcc, tất cả sẽ hoạt động tốt.
Jens Gustyt

Tương tự không có lỗi: stackoverflow.com/questions/9225567/
Ấn

Với gcc hoặc clang, bạn nên chỉ định -std=c11hoặc phiên bản của tiêu chuẩn bạn đang sử dụng. Điều đó bắt lỗi này và các lỗi khác. Tôi cũng đề nghị -Wall -Wextra -Wpedantic -Wconversionít nhất.
Davislor 16/12/18

Câu trả lời:


164

Tiêu chuẩn ISO C99 chỉ định rằng các macro này chỉ phải được xác định nếu được yêu cầu rõ ràng.

#define __STDC_FORMAT_MACROS
#include <inttypes.h>

... now PRIu64 will work

@Dan, đừng quên đánh dấu câu trả lời là được chấp nhận (nhấp vào hình ảnh đánh dấu bên trái) nếu nó giải quyết vấn đề của bạn.
zneak

9
Hừm, chỉ bao gồm tiêu đề là đủ. Các __STDC_FORMAT_MACROSvĩ mô chỉ được yêu cầu để đưa vào C ++.
Jens Gustyt

15
@Jens: Thật vậy; __STDC_FORMAT_MACROSchỉ xuất hiện trong phần chú thích trong C99, cho thấy C ++ chỉ xác định các macro này khi có yêu cầu. Tuy nhiên, ủy ban C ++ đã chọn bỏ qua đề xuất: ví dụ: trong dự thảo n3242, 27.9.2 / 3: Lưu ý: Các macro được xác định bởi <cinttypes> được cung cấp vô điều kiện. Cụ thể, ký hiệu __STDC_FORMAT_MACROS, được đề cập trong chú thích 182 của tiêu chuẩn C, không có vai trò gì trong C ++. Vì vậy, khi trình biên dịch bắt kịp, chúng ta sẽ không cần __STDC_FORMAT_MACROSđến C hoặc C ++.
John Marshall

3
@John Marshall g ++ 4.7.3 dường như yêu cầu macro, ngay cả khi bao gồm <inttypes.h>.
crockeea

4
@Eric: Rõ ràng g ++ 4.7.3 chưa bắt kịp! Trên thực tế, có lẽ bạn đang sử dụng nó với phiên bản glibc có trước bản sửa lỗi này . Như đã thảo luận trong báo cáo glibc đó, libstdc ++ của g ++ 4.7.3 của bạn có mã để khắc phục vấn đề này. Nếu bạn biên dịch với -std=c++0xvà có lẽ #include <cinttypes> thay vì <inttypes.h>, tôi tin rằng nó sẽ cung cấp các macro định dạng mà bạn không cung cấp __STDC_FORMAT_MACROS.
John Marshall

4

Khi biên dịch memcached theo Centos 5.xi cũng gặp vấn đề tương tự.

Giải pháp là nâng cấp ít nhất gcc và g ++ lên phiên bản 4.4.

Đảm bảo CC / CXX của bạn được đặt (xuất) thành nhị phân bên phải trước khi biên dịch.


1

Vì bạn đã bao gồm thẻ C ++, bạn có thể sử dụng thư viện {fmt} và tránh hoàn toàn các vấn đề về PRIu64macro và các printfvấn đề khác :

#include <fmt/core.h>

int main() {
  uint64_t ui64 = 90;
  fmt::print("test uint64_t : {}\n", ui64);
}

Công cụ định dạng dựa trên thư viện này được đề xuất để chuẩn hóa trong C ++ 20: P0645 .

Tuyên bố miễn trừ trách nhiệm : Tôi là tác giả của {fmt}.


Mát mẻ! Có phải nó cũng đến một cái gì đó tương tự sscanf?
ceztko

Hoàn toàn có thể. Chúng tôi đang điều tra khả năng thay thế scanf.
vitaut

Tuyệt quá! Ngoài ra, tôi tự hỏi nếu có tiến bộ đối với một phiên bản có thể lựa chọn độc lập và / hoặc miền địa phương std::to_string(). Trang cppreference vẫn chỉ liên kết đến std::to_chars(), đây không thực sự là những gì mọi người cần. Tôi tự hỏi nếu fmtvà / hoặc c ++ 20 đối phó với nó hay chưa.
ceztko

std::to_stringcó thể sẽ vẫn như cũ, nhưng std::formatcho phép bạn kiểm soát việc có sử dụng miền địa phương hay không (và theo mặc định, nó không sử dụng miền địa phương).
vitaut
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.