Chức năng xác nhận của người dùng là gì?


262

Tôi đã nghiên cứu các hướng dẫn về OpenCV và tìm thấy assertchức năng này; nó làm gì?


20
Lưu ý ghi chú từ man khẳng định: "assert () được triển khai dưới dạng macro; nếu biểu thức được kiểm tra có tác dụng phụ, hành vi chương trình sẽ khác nhau tùy thuộc vào việc NDEBUG có được xác định hay không. Điều này có thể tạo ra Heisenbugs biến mất khi bật gỡ lỗi . "
Julian Schaub - litb


35
@ S.Lott bây giờ mọi người tìm kiếm google sẽ tìm thấy trang này là một trong những kết quả tìm kiếm hàng đầu, cung cấp câu trả lời đánh giá ngang hàng tốt cho câu hỏi của họ và quảng bá Stack Overflow cùng một lúc, vì vậy đó là +1 từ tôi!
Matt Grum

6
Đó là -1 từ tôi. Kết quả tìm kiếm hàng đầu phải là tài liệu mà OP phải tham khảo ngay từ đầu.
Các cuộc đua nhẹ nhàng trong quỹ đạo

9
@LightnessRacesinOrbit. Gọi tôi là lười biếng, nhưng tôi thích sử dụng các bài đọc tài liệu cô đọng, tóm tắt và giải thích tuyệt vời mà người dùng SO có kiến ​​thức như bạn cung cấp. Tôi chân thành cảm ơn :)
Tyson Hilmer

Câu trả lời:


298

assertsẽ chấm dứt chương trình (thường là với một thông báo trích dẫn câu lệnh khẳng định) nếu đối số của nó hóa ra là sai. Nó thường được sử dụng trong quá trình gỡ lỗi để làm cho chương trình thất bại rõ ràng hơn nếu xảy ra tình trạng không mong muốn.

Ví dụ:

assert(length >= 0);  // die if length is negative.

Bạn cũng có thể thêm một thông báo nhiều thông tin hơn sẽ được hiển thị nếu thất bại như vậy:

assert(length >= 0 && "Whoops, length can't possibly be negative! (didn't we just check 10 lines ago?) Tell jsmith");

Hoặc nếu không như thế này:

assert(("Length can't possibly be negative! Tell jsmith", length >= 0));

Khi bạn đang thực hiện bản dựng phát hành (không gỡ lỗi), bạn cũng có thể loại bỏ chi phí đánh giá các assertcâu lệnh bằng cách xác định NDEBUGmacro, thường là bằng một trình chuyển đổi trình biên dịch. Hệ quả của điều này là chương trình của bạn không bao giờ nên dựa vào macro đang hoạt động.

// BAD
assert(x++);

// GOOD
assert(x);    
x++;

// Watch out! Depends on the function:
assert(foo());

// Here's a safer way:
int ret = foo();
assert(ret);

Từ sự kết hợp giữa chương trình gọi abort () và không được đảm bảo để làm bất cứ điều gì, chỉ nên sử dụng các xác nhận để kiểm tra những thứ mà nhà phát triển đã giả sử thay vì, ví dụ, người dùng nhập một số chứ không phải là một chữ cái xử lý bằng các phương tiện khác).


49
" assertthường đưa ra một ngoại lệ" - trong C ++, nó không tăng "ngoại lệ" mà nó gọi là hủy bỏ ... nó hơi khác một chút.
Artyom

5
Tôi không nghĩ câu trả lời này là về các ngôn ngữ giống như câu hỏi được gắn thẻ (C và C ++). Trong C và C ++, khẳng định không đưa ra một ngoại lệ, nó có dấu ngoặc đơn xung quanh đối số của nó và #ký tự không đưa ra nhận xét.
Steve Jessop

Dưới đây là các tùy chọn của bạn: Tạo câu trả lời cho cộng đồng-wiki và chỉnh sửa câu hỏi của bạn để xóa nội dung cũ, yêu cầu người khác đặt thông tin chính xác. Bằng cách đó, downvote sẽ không ảnh hưởng đến đại diện của bạn và mọi người có thể cải thiện câu trả lời.
Julian Schaub - litb

2
chiều dài> = 0 cũng sẽ biến thành sai nếu độ dài là NaN
Andreas

1
Hiện tại, trong VS 2015, xác nhận với thông báo lỗi sẽ không hoạt động vì nó không hoạt động. Nó nên làassert("error message", expression)
Dooskington

102

Các khẳng định tuyên bố máy tính tương tự như báo cáo kết quả chắc chắn bằng tiếng Anh.


131
Vâng, không hoàn toàn. Hãy chắc chắn rằng đèn bị tắt, có nghĩa là, hãy kiểm tra đèn và tắt nó nếu nó bật, không phải là đèn xem nếu đèn tắt và nếu không vui lòng nổ. Tôi muốn nói rằng, hãy kiểm tra hai lần, là một bản dịch gần gũi hơn.
Luke Maurer

7
@Luke, điều đó minh họa cho sự kỳ diệu của ngôn ngữ tiếng Anh, trong đó ngôn ngữ cung cấp nhiều cách để nói điều tương tự. Nhưng hãy xem xét khẳng định (chiều dài> 0). Vì vậy, chúng ta có thể dịch nó thành "kiểm tra kỹ độ dài lớn hơn 0" hoặc "đảm bảo độ dài lớn hơn 0" . Mặc dù rõ ràng cả hai tùy chọn đều hoạt động, tôi vẫn thích của tôi;)
Blake7

4
Chà, nhưng cách giải thích khác là, làm cho độ dài lớn hơn 0. Vì vậy, có một chút mơ hồ.
Luke Maurer

29
Nó gần giống với động từ tiếng Anh "khẳng định"
Steve Carter

Thật vậy, "đảm bảo" có thể được hiểu là "kiểm tra, và nếu không ổn, hãy thay đổi".
Erik Bongers

14

Hãy xem

chương trình ví dụ khẳng định () trong C ++

Nhiều trình biên dịch cung cấp một macro khẳng định (). Macro assert () trả về TRUE nếu tham số của nó đánh giá TRUE và thực hiện một số loại hành động nếu nó đánh giá FALSE. Nhiều trình biên dịch sẽ hủy bỏ chương trình trên một assert () không thành công; những người khác sẽ ném một ngoại lệ

Một tính năng mạnh mẽ của macro khẳng định () là bộ tiền xử lý thu gọn nó thành không có mã nào nếu DEBUG không được xác định. Đó là một sự trợ giúp tuyệt vời trong quá trình phát triển, và khi sản phẩm cuối cùng xuất xưởng, không có hình phạt về hiệu năng cũng như không tăng kích thước của phiên bản thực thi của chương trình.

Ví dụ

#include <stdio.h>
#include <assert.h>

void analyze (char *, int);

int main(void)
{
   char *string = "ABC";
   int length = 3;

   analyze(string, length);
   printf("The string %s is not null or empty, "
          "and has length %d \n", string, length);
}

void analyze(char *string, int length)
{
   assert(string != NULL);     /* cannot be NULL */
   assert(*string != '\0');    /* cannot be empty */
   assert(length > 0);         /* must be positive */
}

/****************  Output should be similar to  ******************
The string ABC is not null or empty, and has length 3

11
Không nên là "nếu NDEBUG được xác định"?
RichN

2
"Nhiều trình biên dịch" nói về cái gì? MSVC và GCC đều tuân thủ các tiêu chuẩn này. Trình biên dịch không tuân thủ nào: không có xác nhận; không in một tin nhắn và hủy bỏ khi xác nhận thất bại; sử dụng DEBUG thay vì NDEBUG thích hợp?
Steve Jessop

lmao, tất nhiên đó là một trang web gọi là java-samples đã hiểu sai điều này.
gạch dưới

6

Hàm assert () có thể chẩn đoán lỗi chương trình. Trong C, nó được định nghĩa trong <assert.h>và trong C ++, nó được định nghĩa trong <cassert>. Nguyên mẫu của nó là

void assert(int expression);

Biểu thức đối số có thể là bất cứ điều gì bạn muốn kiểm tra - một biến hoặc bất kỳ biểu thức C nào. Nếu biểu thức ước lượng thành TRUE, khẳng định () không làm gì cả. Nếu biểu thức ước lượng thành FALSE, assert () hiển thị thông báo lỗi trên stderr và hủy bỏ thực thi chương trình.

Làm thế nào để bạn sử dụng khẳng định ()? Nó thường được sử dụng để theo dõi các lỗi chương trình (khác với các lỗi biên dịch). Một lỗi không ngăn chương trình biên dịch, nhưng nó khiến nó đưa ra kết quả không chính xác hoặc chạy không đúng cách (ví dụ như khóa). Chẳng hạn, một chương trình phân tích tài chính mà bạn viết đôi khi có thể đưa ra câu trả lời không chính xác. Bạn nghi ngờ rằng vấn đề được gây ra bởi biến lãi suất_ lấy một giá trị âm, điều này không bao giờ xảy ra. Để kiểm tra điều này, đặt câu lệnh

khẳng định (lãi_rate> = 0); tại các vị trí trong chương trình nơi lãi suất được sử dụng. Nếu biến không bao giờ trở thành âm, macro xác nhận () sẽ thông báo cho bạn. Sau đó, bạn có thể kiểm tra mã có liên quan để xác định nguyên nhân của vấn đề.

Để xem cách assert () hoạt động, hãy chạy chương trình mẫu bên dưới . Nếu bạn nhập giá trị khác 0, chương trình sẽ hiển thị giá trị và kết thúc bình thường. Nếu bạn nhập số không, macro xác nhận () buộc chấm dứt chương trình bất thường. Thông báo lỗi chính xác mà bạn thấy sẽ phụ thuộc vào trình biên dịch của bạn, nhưng đây là một ví dụ điển hình:

Xác nhận thất bại: x, danh sách tệp19_3.c, dòng 13 Lưu ý rằng, để assert () hoạt động, chương trình của bạn phải được biên dịch trong chế độ gỡ lỗi. Tham khảo tài liệu trình biên dịch của bạn để biết thông tin về việc bật chế độ gỡ lỗi (như được giải thích trong giây lát). Khi bạn biên dịch phiên bản cuối cùng trong chế độ phát hành, các macro xác nhận () sẽ bị tắt.

 int x;

 printf("\nEnter an integer value: ");
 scanf("%d", &x);

 assert(x >= 0);

 printf("You entered %d.\n", x);
 return(0);

Nhập một giá trị số nguyên: 10

Bạn đã nhập 10.

Nhập một giá trị số nguyên: -1

Thông báo lỗi: chấm dứt chương trình bất thường

Thông báo lỗi của bạn có thể khác nhau, tùy thuộc vào hệ thống và trình biên dịch của bạn, nhưng ý tưởng chung là như nhau.


Bạn đã giải thích cách chương trình mẫu của bạn hoạt động với khẳng định. Không phải cách khẳng định chính nó hoạt động. Làm thế nào để nó kết thúc chương trình bất thường? nó ném một số loại ngoại lệ? Loại nào? Liệu nó có tạo ra một tín hiệu đặc biệt? tín hiệu gì? Các xác nhận có thể bị "bắt" bởi bất kỳ loại cơ chế thử bắt C ++ nào không?
Motti Shneor

4

Những thứ như 'tăng ngoại lệ' và 'tạm dừng thực thi' có thể đúng với hầu hết các trình biên dịch, nhưng không phải cho tất cả. (BTW, có những tuyên bố khẳng định thực sự đưa ra ngoại lệ không?)

Đây là một ý nghĩa thú vị, hơi khác của khẳng định được sử dụng bởi c6x và các trình biên dịch TI khác: khi thấy các tuyên bố khẳng định nhất định, các trình biên dịch này sử dụng thông tin trong câu lệnh đó để thực hiện các tối ưu hóa nhất định. Xấu xa.

Ví dụ trong C:

int dot_product(short *x, short *y, short z)
{
  int sum = 0
  int i;

  assert( ( (int)(x) & 0x3 ) == 0 );
  assert( ( (int)(y) & 0x3 ) == 0 );

  for( i = 0 ; i < z ; ++i )
    sum += x[ i ] * y[ i ];
  return sum;
}

Điều này cho trình biên dịch de các mảng được căn chỉnh trên các ranh giới 32 bit, do đó trình biên dịch có thể tạo ra các hướng dẫn cụ thể được thực hiện cho loại căn chỉnh đó.


1
Vậy họ sẽ làm gì nếu khẳng định là sai và NDEBUG không được đặt? Nếu đây là phiên bản khẳng định từ <assert.h>, thì tiêu chuẩn yêu cầu nó in một tin nhắn và hủy bỏ. Rõ ràng là tiêu chuẩn không nói rằng họ không được phép tối ưu hóa dựa trên sự thật của tuyên bố, nhưng để tuân thủ họ vẫn phải hủy bỏ nếu nó sai.
Steve Jessop

1
họ tuân theo hành vi tiêu chuẩn
stijn

1

Dự thảo tiêu chuẩn C ++ 11 N3337

http://www.open-std.org/jtc1/sc22/wg21/docs/ con / 2012 / n3337.pdf

19.3 Khẳng định

1 Tiêu đề <cassert>, được mô tả trong (Bảng 42), cung cấp một macro để ghi lại các xác nhận chương trình C ++ và một cơ chế để vô hiệu hóa kiểm tra xác nhận.

2 Nội dung giống như tiêu đề thư viện C chuẩn <assert.h>.

Dự thảo tiêu chuẩn C99 N1256

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

7.2 Chẩn đoán <assert.h>

1 Tiêu đề <assert.h>xác định macro xác nhận và tham chiếu đến một macro khác, NDEBUGkhông được xác định bởi <assert.h>. Nếu NDEBUGđược định nghĩa là tên macro tại điểm trong tệp nguồn có chứa <assert.h>, macro xác nhận được định nghĩa đơn giản là

 #define assert(ignore) ((void)0)

Macro xác nhận được xác định lại theo trạng thái hiện tại của NDEBUG mỗi lần <assert.h>được đưa vào.

2. Macro khẳng định sẽ được thực hiện như một macro, không phải là một hàm thực tế. Nếu định nghĩa macro bị chặn để truy cập một chức năng thực tế, hành vi không được xác định.

7.2.1 Chẩn đoán chương trình

7.2.1.1 Macro khẳng định

Tóm tắc

1.

#include <assert.h>
void assert(scalar expression);

Sự miêu tả

2 Macro khẳng định đưa các xét nghiệm chẩn đoán vào các chương trình; nó mở rộng đến một biểu thức void. Khi được thực thi, nếu biểu thức (sẽ có kiểu vô hướng) là sai (nghĩa là so sánh bằng 0), macro xác nhận ghi thông tin về cuộc gọi cụ thể không thành công (bao gồm cả văn bản của đối số, tên của tập tin nguồn, số dòng mã nguồn, và tên của hàm chứa nó - sau này lần lượt là các giá trị của các macro tiền xử lý __FILE____LINE__và các định danh __func__) trên dòng sai số chuẩn trong một định dạng thực hiện xác định. 165) Sau đó gọi hàm hủy bỏ.

Trả về

3 Macro khẳng định trả về không có giá trị.


1

Có ba lý do chính để sử dụng hàm assert () so với bình thường nếu khác và printf

  1. Hàm assert () chủ yếu được sử dụng trong giai đoạn gỡ lỗi, thật tẻ nhạt khi viết nếu khác với câu lệnh printf mỗi khi bạn muốn kiểm tra một điều kiện thậm chí không thể thực hiện theo mã cuối cùng.

  2. Trong các triển khai phần mềm lớn, assert rất tiện dụng khi bạn có thể làm cho trình biên dịch bỏ qua các câu lệnh khẳng định bằng cách sử dụng macro NDEBUG được xác định trước khi liên kết tệp tiêu đề cho hàm assert ().

  3. assert () trở nên hữu ích khi bạn đang thiết kế một hàm hoặc một số mã và muốn có ý tưởng về những gì giới hạn mã sẽ và không hoạt động và cuối cùng bao gồm một nếu khác để đánh giá về cơ bản nó chơi với các giả định.


0

Đây là một hàm sẽ dừng thực thi chương trình nếu giá trị mà nó đã đánh giá là sai. Thông thường nó được bao quanh bởi một macro để nó không được biên dịch thành nhị phân kết quả khi được biên dịch với các cài đặt phát hành.

Nó được thiết kế để được sử dụng để kiểm tra các giả định bạn đã thực hiện. Ví dụ:

void strcpy(char* dest, char* src){
    //pointers shouldn't be null
    assert(dest!=null);
    assert(src!=null);

    //copy string
    while(*dest++ = *src++);
}

Lý tưởng bạn muốn là bạn có thể tạo ra lỗi trong chương trình của mình, như gọi một hàm có đối số không hợp lệ và bạn nhấn một xác nhận trước khi nó phân tách (hoặc không hoạt động như mong đợi)


Tại sao chúng ta không sử dụng if & other & thêm một số thông tin đăng nhập?
Asad Khan

1
Bởi vì bạn không bao giờ nên chuyển một con trỏ null sang strcpy. Đó là một trong những điều không nên xảy ra. Nếu một con trỏ null đã được thông qua, nó chỉ ra rằng một cái gì đó ở mức cao hơn đã bị rối tung. Tốt nhất là bạn cuối cùng phải làm hỏng chương trình do sự cố do các giá trị dữ liệu không mong muốn (có thể là không chính xác hoặc không có giá trị).
Yacoby

-5

Ngoài ra, bạn có thể sử dụng nó để kiểm tra xem phân bổ động có thành công hay không.

Mã ví dụ:

int ** p;
p = new int * [5];      // Dynamic array (size 5) of pointers to int
for (int i = 0; i < 5; ++i) {
    p[i] = new int[3]; // Each i(ptr) is now pointing to a dynamic
                       // array (size 3) of actual int values
}

assert (p);            // Check the dynamic allocation.

Tương tự như:

if (p == NULL) {
    cout << "dynamic allocation failed" << endl;
    exit(1);
}

3
Số newném một ngoại lệ về thất bại phân bổ trừ khi bạn chỉ định nothrow(mà bạn đã không ở đây). Hơn nữa, định dạng của bạn là lạ và exitlà xấu xa.
Các cuộc đua nhẹ nhàng trong quỹ đạo

Có bạn đúng. Tôi quên không thêm. Rất thích xem bạn sẽ sử dụng như thế nào thay vì thoát
Sadikov

1
@Sadikov Bất cứ ai khác sẽ xử lý một tình trạng lỗi như vậy bằng cách sử dụng mã không bị xóa hoàn toàn khi xây dựng ở chế độ phát hành , do đó khiến người dùng của bạn không được bảo vệ và không có hành vi không xác định nếu điều kiện tiên quyết không được thỏa mãn và, nhờ điều này, là không bao giờ kiểm tra và bắt . assert()chỉ để gỡ lỗi và dập tắt những thứ không bao giờ, không bao giờ xảy ra - rất lâu trước khi bản dựng phát hành được thực hiện.
gạch dưới
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.