Sử dụng __FILE__, __LINE__ và __FUNCTION__ trong C ++


158

Giả sử rằng trình biên dịch C ++ của bạn hỗ trợ chúng, có lý do cụ thể nào không sử dụng không __FILE__, __LINE____FUNCTION__cho mục đích ghi nhật ký và gỡ lỗi?

Ví dụ, tôi chủ yếu quan tâm đến việc cung cấp cho người dùng dữ liệu sai lệch, báo cáo số dòng hoặc chức năng không chính xác do tối ưu hóa hoặc thực hiện một cú đánh hiệu suất.

Về cơ bản, tôi có thể tin tưởng __FILE__, __LINE____FUNCTION__để luôn luôn làm điều đúng?


LINE nên làm điều đúng đắn. Tôi đã sử dụng nó và các đoàn hệ của nó một cách rộng rãi, bao gồm PRETTY_FUNCTION . ... Nhưng ... chà, tôi hiện đang xem mã nơi LINE nằm. Có lẽ bởi vì nó nằm trong một khối bắt để xử lý ngoại lệ thử / bắt.
Krazy Glew

Câu trả lời:


191

__FUNCTION__là không chuẩn, __func__tồn tại trong C99 / C ++ 11. Những người khác ( __LINE____FILE__) là tốt.

Nó sẽ luôn báo cáo đúng tệp và dòng (và chức năng nếu bạn chọn sử dụng __FUNCTION__/ __func__). Tối ưu hóa là một yếu tố không phải là một yếu tố vì nó là một mở rộng vĩ mô thời gian biên dịch; Nó sẽ không bao giờ ảnh hưởng đến hiệu suất trong bất kỳ cách nào.


3
__func__là một vấn đề trong C ++. C99 không nói một từ nào về các đối số mặc định và v.v., những trường hợp không rõ ràng về cách __func__hành xử trong C ++.
wilmustell

4
@thr: trong khi bạn làm cho một điểm tốt. Tôi đã khá rõ ràng rằng __func__tồn tại trong c99, không phải c ++. Bất kể, tôi nghĩ rằng việc triển khai hợp lý __func__trong c ++ sẽ chỉ dẫn đến tên bị sai lệch. Vì tôi không phải là người viết trình biên dịch, nó không thực sự là cuộc gọi của tôi.
Evan Teran

Trình biên dịch nào không hỗ trợ __FUNCTION__gì cả? Trình biên dịch nào ngoại trừ gcc gần đây coi đây là một biến, không phải là macro?
lưu vực

36
__func__hiện đang ở chuẩn C ++ 11.
VX

38

Trong những trường hợp hiếm hoi, có thể hữu ích để thay đổi dòng được đưa ra bởi __LINE__một thứ khác. Tôi đã thấy cấu hình GNU thực hiện điều đó đối với một số thử nghiệm để báo cáo số dòng thích hợp sau khi nó chèn một số voodoo giữa các dòng không xuất hiện trong các tệp nguồn gốc. Ví dụ:

#line 100

Sẽ làm cho các dòng sau bắt đầu bằng __LINE__100. Bạn có thể tùy ý thêm tên tệp mới

#line 100 "file.c"

Nó chỉ hiếm khi hữu ích. Nhưng nếu nó là cần thiết, không có lựa chọn thay thế nào tôi biết. Trên thực tế, thay vì dòng, một macro cũng có thể được sử dụng mà phải dẫn đến bất kỳ hình thức nào trong hai hình thức trên. Sử dụng thư viện tiền xử lý boost, bạn có thể tăng dòng hiện tại lên 50:

#line BOOST_PP_ADD(__LINE__, 50)

Tôi nghĩ thật hữu ích khi đề cập đến nó vì bạn đã hỏi về cách sử dụng __LINE____FILE__. Một người không bao giờ có đủ bất ngờ từ C ++ :)

Chỉnh sửa: @Jonathan Leffler cung cấp một số trường hợp sử dụng tốt hơn trong các nhận xét:

Lộn xộn với #line rất hữu ích cho các bộ xử lý trước muốn giữ các lỗi được báo cáo trong mã C của người dùng phù hợp với tệp nguồn của người dùng. Yacc, Lex và (nhiều hơn ở nhà với tôi) bộ tiền xử lý ESQL / C làm điều đó.


29

FYI: g ++ cung cấp macro __PRETTY_FUNCTION__ không chuẩn. Cho đến bây giờ tôi không biết về C99 __func__ (cảm ơn Evan!). Tôi nghĩ rằng tôi vẫn thích __PRETTY_FUNCTION__ khi nó có sẵn cho phạm vi lớp học thêm.

Tái bút

static string  getScopedClassMethod( string thePrettyFunction )
{
  size_t index = thePrettyFunction . find( "(" );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( index );

  index = thePrettyFunction . rfind( " " );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( 0, index + 1 );

  return thePrettyFunction;   /* The scoped class name. */
}

2
Rất vui được biết về __PRETTY_FUNCTION__. Rất hữu ích!
Trịnh Qu

8

Cá nhân, tôi miễn cưỡng sử dụng chúng cho bất cứ điều gì ngoại trừ các thông báo gỡ lỗi. Tôi đã làm điều đó, nhưng tôi cố gắng không hiển thị loại thông tin đó cho khách hàng hoặc người dùng cuối. Khách hàng của tôi không phải là kỹ sư và đôi khi không hiểu biết về máy tính. Tôi có thể đăng nhập thông tin này vào bàn điều khiển, nhưng, như tôi đã nói, miễn cưỡng ngoại trừ các bản dựng gỡ lỗi hoặc cho các công cụ nội bộ. Tôi cho rằng nó phụ thuộc vào cơ sở khách hàng mà bạn có.


29
"Tôi có thể đăng nhập thông tin này vào bảng điều khiển" - hoặc tốt hơn nữa: đăng nhập nó vào một tệp để nếu có sự cố xảy ra, bạn có thể yêu cầu khách hàng gửi nó cho bạn ...
Christoph

7

C ++ 20 std::source_location

C ++ cuối cùng đã thêm một tùy chọn phi vĩ mô và nó có thể sẽ chiếm ưu thế tại một số điểm trong tương lai khi C ++ 20 trở nên phổ biến:

Các tài liệu nói:

constexpr const char * function_name () const noexcept;

6 Trả về: Nếu đối tượng này đại diện cho một vị trí trong phần thân của hàm, trả về một NTBS được xác định theo thực hiện sẽ tương ứng với tên hàm. Nếu không, trả về một chuỗi rỗng.

Trong đó NTBS có nghĩa là "Chuỗi Byte Null chấm dứt".

Tôi sẽ dùng thử khi hỗ trợ đến GCC, GCC 9.1.0 mà g++-9 -std=c++2avẫn không hỗ trợ.

https://en.cppreference.com/w/cpp/utility/source_location yêu cầu sử dụng sẽ như sau:

#include <iostream>
#include <string_view>
#include <source_location>

void log(std::string_view message,
         const std::source_location& location std::source_location::current()
) {
    std::cout << "info:"
              << location.file_name() << ":"
              << location.line() << ":"
              << location.function_name() << " "
              << message << '\n';
}

int main() {
    log("Hello world!");
}

Sản lượng có thể:

info:main.cpp:16:main Hello world!

__PRETTY_FUNCTION__đấu __FUNCTION__với __func__vsstd::source_location::function_name

Đã trả lời tại: Sự khác biệt giữa __PRETTY_FUNCTION__, __FUNCTION__, __func__ là gì?


1
<experimental/source_location>trong gcc-9 hiện tại.
陈浩南

5

Tôi sử dụng tất cả các thời gian. Điều duy nhất tôi lo lắng là cho đi IP trong các tệp nhật ký. Nếu tên hàm của bạn thực sự tốt, bạn có thể làm cho một bí mật thương mại dễ dàng khám phá hơn. Nó giống như vận chuyển với các biểu tượng gỡ lỗi, chỉ khó khăn hơn để tìm thấy mọi thứ. Trong 99,999% các trường hợp sẽ không có gì xấu xảy ra.


1
Điểm tốt để đưa lên. Việc trích xuất thông tin này bằng cách sử dụng stringstiện ích để trích xuất tất cả dữ liệu giống như chuỗi từ tệp thực thi là điều không quan trọng. Ngay cả thực thi nén có thể được trích xuất. Hãy rất chú ý đến những gì bạn gửi đến một trang web của khách hàng. Thông thường các đối thủ cạnh tranh có thể có được bàn tay của bạn trên thực thi của bạn, mặc dù họ không cần phải làm như vậy.
Marty
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.