2012-03-14 51 views
7
00001 /* assert.h 
00002 Copyright (C) 2001, 2003 Free Software Foundation, Inc. 
00003 Written by Stephane Carrez ([email protected])  
00004 
00005 This file is free software; you can redistribute it and/or modify it 
00006 under the terms of the GNU General Public License as published by the 
00007 Free Software Foundation; either version 2, or (at your option) any 
00008 later version. 
00009 
00010 In addition to the permissions in the GNU General Public License, the 
00011 Free Software Foundation gives you unlimited permission to link the 
00012 compiled version of this file with other programs, and to distribute 
00013 those programs without any restriction coming from the use of this 
00014 file. (The General Public License restrictions do apply in other 
00015 respects; for example, they cover modification of the file, and 
00016 distribution when not linked into another program.) 
00017 
00018 This file is distributed in the hope that it will be useful, but 
00019 WITHOUT ANY WARRANTY; without even the implied warranty of 
00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
00021 General Public License for more details. 
00022 
00023 You should have received a copy of the GNU General Public License 
00024 along with this program; see the file COPYING. If not, write to 
00025 the Free Software Foundation, 59 Temple Place - Suite 330, 
00026 Boston, MA 02111-1307, USA. */ 
00027 
00028 #ifndef _ASSERT_H 
00029 #define _ASSERT_H 
00030 
00031 #ifdef NDEBUG 
00032 # define assert(EX) 
00033 #else 
00034 # define assert(EX) (void)((EX) || (__assert (#EX, __FILE__, __LINE__),0)) 
00035 #endif 
00036 
00037 #ifdef __cplusplus 
00038 extern "C" { 
00039 #endif 
00040 
00041 extern void __assert (const char *msg, const char *file, int line); 
00042 
00043 #ifdef __cplusplus 
00044 }; 
00045 #endif 
00046 #endif 

Câu hỏi đặt ra là: "khoảng trống" trên dòng 34 và __assert là gì?C++ khẳng định việc triển khai trong assert.h

Trả lời

11

Look az dòng này:

extern void __assert (const char *msg, const char *file, int line); 

__assert là chức năng mà phải mất một thông điệp khẳng định, một tên tập tin và một số dòng như các đối số. Về cơ bản, đây là phương thức in ra thông báo lỗi và kết thúc chương trình khi xác nhận không thành công.

Sau đó nhìn vào định nghĩa macro trên:

#define assert(EX) (void)((EX) || (__assert (#EX, __FILE__, __LINE__),0)) 

Nó định nghĩa các assert(EX) vĩ mô như vậy, nó sẽ kiểm tra đầu tiên khái niệm và EX (vì các hoạt động ngắn mạch của các nhà điều hành C++ ||) chỉ khi nó không thành công, nó gọi hàm __assert và chuyển ngoại lệ khẳng định không thành công dưới dạng chuỗi và vị trí chính xác của lệnh gọi phương thức assert() trong tệp nguồn của bạn. Với thủ đoạn gian trá tiền xử lý này thư viện khẳng định đạt được rằng khi bạn gõ như sau trong chương trình của bạn

assert(a == 0); 

và khẳng định của bạn bị lỗi trong quá trình chạy chương trình, bạn nhận được thông báo

Assertion failed: a == 0 at program.c, line 23 

lỗi chi tiết giúp bạn xác định vị trí chính xác nơi xác nhận không thành công trong mã của bạn.

Phần (void) chỉ để đảm bảo rằng trình biên dịch sẽ không đưa ra một số cảnh báo về kết quả không sử dụng của biểu thức (EX) || 0, hãy xem các câu trả lời khác, những người giải thích rõ.

Bộ tiền xử lý còn lại xác định NDEBUG được sử dụng để biến thế hệ khẳng định ở tất cả thời gian biên dịch, bạn thực thi kết quả của bạn sẽ nhỏ hơn và nhanh hơn.

+0

Tất cả các quyền, hoàn hảo, nhờ giải thích chi tiết. Chỉ có hai câu hỏi: 1) Tại sao (__assert (#EX, __FILE__, __LINE __), 0) nó được sử dụng ", 0" và 2) Tại sao (cơ chế nào) ngăn chặn cảnh báo của trình biên dịch khi bạn bool bool void? Có phải vì khoảng trống không là gì cả ??? – Narek

+4

1) [toán tử dấu phẩy] (http://en.wikipedia.org/wiki/Comma_operator) (',') đầu tiên thực thi biểu thức bên trái (gọi hàm '__assert') rồi biểu thức bên phải (chữ' ' 0') và trả về kết quả sau. Nó là cần thiết vì toán tử '||' mong đợi toán hạng tương thích boolean, nhưng hàm '__assert' trả về' void'. – buc

+4

2) Hãy tưởng tượng một câu lệnh '(a == 3) || (0); 'một mình trên một dòng. Nó không có ý nghĩa nhiều để thực hiện một so sánh và sau đó không làm gì với kết quả. Trình biên dịch cũng nhận ra điều này và nghi ngờ rằng bạn đã quên hoàn thành câu lệnh và cảnh báo bạn về nó. Bằng cách truyền toàn bộ biểu thức sang 'void':' (void) ((a == 3) || (0)) 'bạn nói với trình biên dịch rằng biểu thức này không có giá trị kết quả hợp lý (giống như lời gọi tới' void'- chức năng trả về cũng sẽ không có), vì vậy nó sẽ không phàn nàn về nó. – buc

1

Nó ngăn chặn cảnh báo trình biên dịch về các giá trị hoặc biến không sử dụng.

Cũng lưu ý toán tử dấu phẩy ở bên phải, làm cho cả hai mặt của || có thể chuyển đổi thành bool.

__assert là chức năng nội bộ có thể in tin nhắn và thực hiện hành vi xác nhận bắt buộc (ví dụ: gọi abort()).

7

__assert là một phần của quá trình triển khai; trong trường hợp này, một hàm trong thư viện sẽ được gọi trong trường hợp lỗi xác nhận. Và (void) chỉ đơn giản là tắt cảnh báo trình biên dịch về kết quả không sử dụng của toán tử ||.

1

Hầu hết ...

xem xét: assert(a == 0); này được mở rộng để

(void)((a == 0) || (__assert (#a == 0, __FILE__, __LINE__),0))

Nếu bạn có những biểu hiện (x || y) - Trong trường hợp này cả x và y đánh giá như bools, vì vậy nếu 'a' evals 0, định nghĩa of || nói để thử bool tiếp theo trong dòng, tức là 'y'

Vì vậy - nếu xác nhận của bạn là sai, (__assert (#a == 0, __FILE__, __LINE__),0) được đánh giá, có nghĩa là __assert() được gọi.

Tại sao (__assert(), 0) ?? __assert là hàm được định nghĩa là void __assert() - cũng ... hầu hết thời gian. xem http://www.opensource.apple.com/source/Libc/Libc-825.26/include/assert.h cho một bộ macro khẳng định() - lưu ý rằng tất cả chúng kết thúc bằng cách gọi một hàm ...

Toán tử dấu phẩy cho phép bạn thực hiện hai điều trong cùng một câu lệnh, nghĩa là i++, j++ - nhưng hãy nhớ một biểu thức phải đánh giá thành một số giá trị - trong trường hợp này là "0" - vì vậy toàn bộ câu lệnh đánh giá là (void)(0 || 0) là biểu thức hợp lệ. Là một tác dụng phụ, biểu thức của bạn được đánh giá và có thể một hàm được gọi.

Lưu ý trong (void)(0 || 0) số 0 đầu tiên từ xác nhận không thành công của bạn. Điều này có thể được tạo tại thời gian biên dịch nếu xác nhận của bạn đánh giá thứ gì đó mà trình biên dịch có thể tạo dưới dạng hằng số hoặc biểu thức được đánh giá, tức là (void)((a == 0) || 0)

lưu ý dấu phẩy ", 0" là dành cho trình biên dịch thực sự. không thấy nó. Nhưng (a || __assert()) là rất phổ biến. Bạn có thể viết macro là

#define assert(x) { if(! (x)) __assert(.....); } 
Các vấn đề liên quan