Đây là lệnh perlhacktips có thể chạy trong nhà cung cấp dịch vụ lưu trữ miễn phí OnWorks bằng cách sử dụng một trong nhiều máy trạm trực tuyến miễn phí của chúng tôi như Ubuntu Online, Fedora Online, trình giả lập trực tuyến Windows hoặc trình giả lập trực tuyến MAC OS
CHƯƠNG TRÌNH:
TÊN
perlhacktips - Mẹo hack mã Perl core C
MÔ TẢ
Tài liệu này sẽ giúp bạn tìm hiểu cách tốt nhất để tiếp tục hack trên Perl core C
mã số. Nó bao gồm các vấn đề phổ biến, gỡ lỗi, lập hồ sơ và hơn thế nữa.
Nếu bạn chưa đọc perlhack và perlhacktut, bạn có thể muốn làm điều đó trước.
CHUNG VẤN ĐỀ
Nguồn Perl phát theo quy tắc ANSI C89: không có phần mở rộng C99 (hoặc C ++). Trong một số trường hợp, chúng tôi phải
xem xét các yêu cầu trước ANSI. Bạn không quan tâm đến một số cụ thể
nền tảng bị hỏng Perl? Tôi nghe nói rằng vẫn có nhu cầu lớn về lập trình viên J2EE.
Perl môi trường vấn đề
· Không biên dịch với luồng
Biên dịch với phân luồng (-Duseithreads) viết lại hoàn toàn các nguyên mẫu hàm
của Perl. Tốt hơn bạn nên thử những thay đổi của mình với điều đó. Liên quan đến điều này là sự khác biệt
giữa các API "Perl_-less" và "Perl_-ly", ví dụ:
Perl_sv_setiv (aTHX_ ...);
sv_setiv (...);
Cái đầu tiên chuyển một cách rõ ràng trong ngữ cảnh, cần cho ví dụ: luồng
xây dựng. Người thứ hai làm điều đó một cách ngầm hiểu; không để chúng trộn lẫn. Nếu bạn không phải là
chuyển vào aTHX_, bạn sẽ cần thực hiện dTHX (hoặc dVAR) như là điều đầu tiên trong
chức năng.
Xem "Cách hỗ trợ nhiều trình thông dịch và đồng thời" trong perlguts để biết thêm
thảo luận về bối cảnh.
· Không biên dịch với -DDEBUGGING
Định nghĩa DEBUGGING đưa ra nhiều mã hơn cho trình biên dịch, do đó có nhiều cách hơn cho mọi thứ
Đi sai. Bạn nên thử nó.
· Giới thiệu hình cầu (không-chỉ-đọc)
Không giới thiệu bất kỳ hình cầu có thể sửa đổi nào, thực sự toàn cầu hoặc tệp tĩnh. Họ rất tệ
hình thành và làm phức tạp đa luồng và các hình thức đồng thời khác. Cách đúng đắn là
để giới thiệu chúng dưới dạng các biến thông dịch mới, hãy xem intrpvar.h (cuối cùng cho
khả năng tương thích nhị phân).
Việc giới thiệu hình cầu chỉ đọc (const) là được, miễn là bạn xác minh bằng ví dụ: "nm
libperl.a | egrep -v '[TURtr]' "(nếu" nm "của bạn có đầu ra kiểu BSD) mà dữ liệu bạn
được thêm vào thực sự là chỉ đọc. (Nếu có, nó sẽ không hiển thị trong đầu ra của
chỉ huy.)
Nếu bạn muốn có chuỗi tĩnh, hãy làm cho chúng không đổi:
static const char etc [] = "...";
Nếu bạn muốn có các mảng chuỗi không đổi, hãy lưu ý cẩn thận để kết hợp đúng
của "const" s:
static const char * const yippee [] =
{"chào", "ho", "bạc"};
Có một cách để ẩn hoàn toàn bất kỳ khối cầu có thể sửa đổi nào (tất cả chúng đều được chuyển vào heap),
cài đặt biên dịch "-DPERL_GLOBAL_THER_PRIVATE". Nó không được sử dụng bình thường, nhưng
có thể được sử dụng để thử nghiệm, hãy đọc thêm về nó trong "Nền và PERL_IMPLICIT_CONTEXT"
trong perlguts.
· Không xuất chức năng mới của bạn
Một số nền tảng (Win32, AIX, VMS, OS / 2, tên một số nền tảng) yêu cầu bất kỳ chức năng nào
một phần của API công khai (thư viện Perl được chia sẻ) sẽ được đánh dấu rõ ràng là đã xuất.
Xem cuộc thảo luận về nhúng.pl trong perlguts.
· Xuất chức năng mới của bạn
Kết quả sáng bóng mới của chức năng mới chính hãng hoặc quá trình tái cấu trúc gian khổ của bạn
hiện đã sẵn sàng và được xuất một cách chính xác. Vậy điều gì có thể xảy ra?
Có thể đơn giản là ngay từ đầu, hàm của bạn không cần xuất. Perl
có một lịch sử lâu dài và không huy hoàng về các chức năng xuất khẩu mà nó không nên có.
Nếu hàm chỉ được sử dụng bên trong một tệp mã nguồn, hãy đặt nó ở trạng thái tĩnh. Xem
Thảo luận về nhúng.pl trong perlguts.
Nếu hàm được sử dụng trên nhiều tệp, nhưng chỉ dành cho nội bộ của Perl
sử dụng (và đây phải là trường hợp phổ biến), không xuất nó sang API công khai. Xem
Thảo luận về nhúng.pl trong perlguts.
Tính di động vấn đề
Sau đây là những nguyên nhân phổ biến gây ra lỗi biên dịch và / hoặc thực thi, không phổ biến đối với
Perl như vậy. Câu hỏi thường gặp về C là cách đọc tốt trước khi đi ngủ. Vui lòng kiểm tra các thay đổi của bạn với càng nhiều C
trình biên dịch và nền tảng càng tốt; dù sao thì chúng tôi cũng sẽ làm và thật tuyệt khi tự cứu mình khỏi
sự bối rối của công chúng.
Nếu sử dụng gcc, bạn có thể thêm tùy chọn "-std = c89", hy vọng sẽ bắt được hầu hết các
không có khả năng thanh toán. (Tuy nhiên, nó cũng có thể bắt gặp sự không tương thích trong tiêu đề hệ thống của bạn
các tập tin.)
Sử dụng cờ Định cấu hình "-Dgccansipedantic" để bật cờ gcc "-ansi -pedantic"
thực thi các quy tắc ANSI nghiêm ngặt hơn.
Nếu sử dụng "gcc -Wall", hãy lưu ý rằng không phải tất cả các cảnh báo có thể có (như "-Wunitialized")
được đưa ra trừ khi bạn cũng biên dịch với "-O".
Lưu ý rằng nếu sử dụng gcc, hãy bắt đầu từ Perl 5.9.5, các tệp mã nguồn lõi Perl (những
ở cấp cao nhất của phân phối mã nguồn, nhưng không phải là các phần mở rộng trong ext /)
được tự động biên dịch với càng nhiều "-std = c89", "-ansi",
"-pedantic" và lựa chọn các cờ "-W" (xem cflags.SH).
Cũng nghiên cứu kỹ về perlport để tránh bất kỳ giả định xấu nào về hệ điều hành,
hệ thống tập tin, bộ ký tự, v.v.
Thỉnh thoảng bạn có thể thử "make microperl" để xem liệu chúng ta có thể biên dịch Perl hay không
chỉ với số lượng giao diện tối thiểu. (Xem README.micro.)
Đừng cho rằng một hệ điều hành chỉ ra một trình biên dịch nhất định.
· Truyền con trỏ tới số nguyên hoặc truyền số nguyên tới con trỏ
void castaway (U8 * p)
{
IV tôi = p;
or
void castaway (U8 * p)
{
IV i = (IV) p;
Cả hai đều xấu, hỏng hóc và không thể di chuyển được. Sử dụng PTR2IV () macro làm đúng.
(Tương tự như vậy, có PTR2UV (), PTR2NV (), INT2PTR ()và NUM2PTR ().)
· Truyền giữa con trỏ hàm và con trỏ dữ liệu
Nói về mặt kỹ thuật, việc truyền giữa con trỏ hàm và con trỏ dữ liệu là không thể di chuyển được
và không xác định, nhưng thực tế mà nói, nó có vẻ hoạt động, nhưng bạn nên sử dụng
FPTR2DPTR () và DPTR2FPTR () macro. Đôi khi bạn cũng có thể chơi trò chơi với các đoàn thể.
· Giả sử sizeof (int) == sizeof (long)
Có các nền tảng trong đó long là 64 bit và các nền tảng có int là 64 bit, và
trong khi chúng tôi sẵn sàng gây sốc cho bạn, ngay cả những nền tảng mà quần short là 64 bit. Đây là tất cả
hợp pháp theo tiêu chuẩn C. (Nói cách khác, "dài dài" không phải là một cách di động
để chỉ định 64 bit và "long long" thậm chí không được đảm bảo rộng hơn
"Dài".)
Thay vào đó, hãy sử dụng các định nghĩa IV, UV, IVSIZE, I32SIZE, v.v. Tránh những thứ như
I32 bởi vì họ là không đảm bảo là chính xác 32 bit, chúng là at ít nhất 32 bit,
chúng cũng không được đảm bảo là int or Dài. Nếu bạn thực sự cần 64-bit một cách rõ ràng
, sử dụng I64 và U64, nhưng chỉ khi được bảo vệ bởi HAS_QUAD.
· Giả sử người ta có thể bỏ qua bất kỳ loại con trỏ nào cho bất kỳ loại dữ liệu nào
char * p = ...;
ngựa dài = * p; /* TỒI TỆ */
Nhiều nền tảng, hoàn toàn đúng như vậy, sẽ cung cấp cho bạn một kết xuất lõi thay vì một con ngựa nếu p
xảy ra không được căn chỉnh chính xác.
· Phôi giá trị
(int) * p = ...; /* TỒI TỆ */
Chỉ đơn giản là không di động. Đặt giá trị của bạn đúng loại hoặc có thể sử dụng tạm thời
những biến tướng, hoặc những thủ đoạn bẩn thỉu với các nghiệp đoàn.
· Thừa nhận bất cứ điều gì về cấu trúc (đặc biệt là những cấu trúc bạn không kiểm soát, như cấu trúc
đến từ tiêu đề hệ thống)
· Rằng một trường nhất định tồn tại trong một cấu trúc
· Không có trường nào khác tồn tại ngoài những trường bạn biết
· Trường đó có độ ký, kích thước hoặc kiểu nhất định
· Rằng các trường theo thứ tự nhất định
· Trong khi C đảm bảo thứ tự được chỉ định trong định nghĩa struct,
giữa các nền tảng khác nhau, các định nghĩa có thể khác nhau
· Kích thước của (struct) hoặc các căn chỉnh giống nhau ở mọi nơi
· Có thể có các byte đệm giữa các trường để căn chỉnh các trường -
các byte có thể là bất cứ thứ gì
· Các cấu trúc được yêu cầu phải được căn chỉnh theo yêu cầu căn chỉnh tối đa
bởi các trường - đối với các kiểu gốc thường tương đương với
sizeof () của cánh đồng
· Giả sử bộ ký tự là ASCIIish
Perl có thể biên dịch và chạy dưới nền tảng EBCDIC. Xem perlebcdic. Đây là minh bạch
đối với hầu hết các phần, nhưng vì các bộ ký tự khác nhau, bạn không nên sử dụng số
(thập phân, bát phân, cũng không phải hex) để tham chiếu đến các ký tự. Bạn có thể nói 'A' một cách an toàn,
nhưng không phải 0x41. Bạn có thể nói "\ n" một cách an toàn chứ không phải "\ 012". Tuy nhiên, bạn có thể sử dụng macro
được định nghĩa trong utf8.h để chỉ định bất kỳ điểm mã nào một cách di động. "LATIN1_TO_NATIVE(0xDF) "là
sẽ là điểm mã có nghĩa là CHIA SẺ CHỮ CÁI NHỎ LATIN trên bất kỳ nền tảng nào
bạn đang chạy (trên nền tảng ASCII, nó biên dịch mà không cần thêm bất kỳ mã bổ sung nào, vì vậy
không có hiệu suất đánh vào những). Các đầu vào được chấp nhận cho "LATIN1_TO_NATIVE"
là từ 0x00 đến 0xFF. Nếu đầu vào của bạn không được đảm bảo nằm trong phạm vi đó, hãy sử dụng
"UNICODE_TO_NATIVE" để thay thế. "NATIVE_TO_LATIN1" và "NATIVE_TO_UNICODE" dịch
theo hướng ngược lại.
Nếu bạn cần biểu diễn chuỗi của một ký tự không có tên dễ nhớ
trong C, bạn nên thêm nó vào danh sách trong regen / unicode_constants.plvà có Perl
tạo "#define" cho bạn, dựa trên nền tảng hiện tại.
Lưu ý rằng dấu "làFOO " và "đểFOO " macro trong tiện dụng.h hoạt động bình thường trên mã gốc
điểm và chuỗi.
Ngoài ra, phạm vi 'A' - 'Z' trong ASCII là một chuỗi liên tục gồm 26 chữ cái viết hoa
nhân vật. Điều đó không đúng trong EBCDIC. Cũng không phải cho 'a' thành 'z'. Nhưng '0' - '9' là một
phạm vi không bị gián đoạn trong cả hai hệ thống. Đừng giả định bất cứ điều gì về các phạm vi khác. (Lưu ý rằng
xử lý đặc biệt các phạm vi trong các mẫu biểu thức chính quy làm cho nó xuất hiện với mã Perl
rằng các phạm vi nói trên đều không bị gián đoạn.)
Nhiều nhận xét trong mã hiện tại bỏ qua khả năng của EBCDIC và có thể
do đó sai, ngay cả khi mã hoạt động. Đây thực sự là một lời tri ân cho sự thành công
chèn minh bạch về khả năng xử lý EBCDIC mà không cần phải thay đổi trước
mã hiện có.
UTF-8 và UTF-EBCDIC là hai bảng mã khác nhau được sử dụng để biểu thị các điểm mã Unicode
dưới dạng chuỗi byte. Các macro có cùng tên (nhưng định nghĩa khác nhau) trong
utf8.h và utfebcdic.h được sử dụng để cho phép mã gọi điện nghĩ rằng chỉ có
một mã hóa như vậy. Điều này hầu như luôn được gọi là "utf8", nhưng nó có nghĩa là
Phiên bản EBCDIC cũng vậy. Một lần nữa, các nhận xét trong mã cũng có thể sai ngay cả khi
mã chính nó là đúng. Ví dụ: khái niệm UTF-8 "ký tự bất biến"
khác nhau giữa ASCII và EBCDIC. Trên nền tảng ASCII, chỉ các ký tự không
có bộ bit bậc cao (tức là thứ tự của nó là ASCII nghiêm ngặt, 0 - 127) là
bất biến, và tài liệu và nhận xét trong mã có thể giả định rằng, thường
đề cập đến một cái gì đó như, nói, "hibit". Tình hình khác và không đơn giản như vậy
trên máy EBCDIC, nhưng miễn là bản thân mã sử dụng "NATIVE_IS_INVARIANT ()"
macro một cách thích hợp, nó hoạt động, ngay cả khi các nhận xét sai.
Như đã lưu ý trong phần "KIỂM TRA" trong perlhack, khi viết các tập lệnh kiểm tra, tệp
t / charset_tools.pl chứa một số chức năng hữu ích để viết các bài kiểm tra hợp lệ trên cả hai
Nền tảng ASCII và EBCDIC. Tuy nhiên, đôi khi, một bài kiểm tra không thể sử dụng một hàm và nó
bất tiện khi có các phiên bản thử nghiệm khác nhau tùy thuộc vào nền tảng. Có 20
các điểm mã giống nhau trong cả 4 bộ ký tự hiện được Perl công nhận
(3 trang mã EBCDIC cộng với ISO 8859-1 (ASCII / Latin1)). Chúng có thể được sử dụng trong
thử nghiệm, mặc dù có một khả năng nhỏ là Perl sẽ có sẵn trong
một bộ ký tự khác, phá vỡ bài kiểm tra của bạn. Tất cả trừ một trong những điểm mã này là C0
các ký tự điều khiển. Các điều khiển quan trọng nhất giống nhau là "\ 0", "\ r",
và "\ N {VT}" (cũng có thể xác định là "\ cK", "\ x0B", "\ N {U + 0B}" hoặc "\ 013"). Duy nhất
không điều khiển là U + 00B6 PILCROW SIGN. Các điều khiển giống nhau có cùng một bit
mẫu trong tất cả 4 bộ ký tự, bất kể UTF8ness của chuỗi chứa
họ. Mẫu bit cho U + B6 giống nhau ở cả 4 chuỗi không phải UTF8, nhưng khác
trong mỗi khi chuỗi chứa của nó được mã hóa UTF-8. Mã duy nhất khác chỉ ra rằng
có một số loại giống nhau trên tất cả 4 bộ ký tự là cặp 0xDC và 0xFC.
Cùng nhau, chúng đại diện cho CHỮ LATIN viết hoa và viết thường U VỚI DIAERESIS, nhưng
là chữ trên và chữ viết dưới có thể bị đảo ngược: 0xDC là chữ viết hoa trong tiếng Latinh1 và 0xFC là
chữ cái nhỏ, trong khi 0xFC là vốn trong EBCDIC và 0xDC là chữ cái nhỏ. Điều này
factoid có thể được khai thác để viết các bài kiểm tra không phân biệt chữ hoa chữ thường giống nhau trên
tất cả 4 bộ ký tự.
· Giả sử bộ ký tự chỉ là ASCII
ASCII là một mã hóa 7 bit, nhưng các byte có 8 bit trong đó. 128 ký tự phụ
có ý nghĩa khác nhau tùy thuộc vào ngôn ngữ. Không có ngôn ngữ, hiện tại
các ký tự phụ thường được coi là chưa được gán và điều này đã được trình bày
một số vấn đề. Điều này đã được thay đổi bắt đầu từ 5.12 để các ký tự này có thể
được coi là tiếng Latinh-1 (ISO-8859-1).
· Trộn #define và #ifdef
#define BURGLE (x) ... \
#ifdef BURGLE_OLD_STYLE / * BAD * /
... làm theo cách cũ ... \
#khác
... làm theo cách mới ... \
#endif
Bạn không thể di chuyển các chỉ thị cpp "ngăn xếp". Ví dụ ở trên, bạn cần hai
riêng biệt BURGLE () #defines, một cho mỗi nhánh #ifdef.
· Thêm nội dung không phải nhận xét sau #endif hoặc #else
#ifdef SNOSH
...
#else! SNOSH / * BAD * /
...
#endif SNOSH / * BAD * /
#Endif và #else chắc chắn không thể có bất kỳ điều gì không nhận xét sau chúng. nếu bạn
muốn ghi lại những gì đang diễn ra (đó là một ý tưởng hay, đặc biệt nếu các chi nhánh
dài), sử dụng (C) nhận xét:
#ifdef SNOSH
...
#else / *! SNOSH * /
...
#endif / * SNOSH * /
Tùy chọn gcc "-Wendif-label" cảnh báo về biến thể xấu (theo mặc định khi bắt đầu
từ Perl 5.9.4).
· Có dấu phẩy sau phần tử cuối cùng của danh sách enum
màu enum {
hạt ngũ cốc,
điều lệ,
CINNABAR, / * BAD * /
};
không phải là di động. Bỏ dấu phẩy cuối cùng.
Cũng lưu ý rằng liệu enums có thể trộn lẫn hoàn toàn với int khác nhau giữa các
trình biên dịch, bạn có thể cần (int).
· Sử dụng // - bình luận
// Hàm này bamfoodles zorklator. /* TỒI TỆ */
Đó là C99 hoặc C ++. Perl là C89. Sử dụng // - nhận xét được cho phép bởi nhiều C
trình biên dịch nhưng tăng cường độ nghiêm ngặt ANSI C89 (mà chúng tôi muốn làm) gây ra
biên dịch không thành công.
· Trộn các khai báo và mã
void zorklator ()
{
int n = 3;
set_zorkmids (n); /* TỒI TỆ */
int q = 4;
Đó là C99 hoặc C ++. Một số trình biên dịch C cho phép điều đó, nhưng bạn không nên.
Tùy chọn gcc "-Khai báo sau câu lệnh" quét các sự cố như vậy (theo mặc định là bật
bắt đầu từ Perl 5.9.4).
· Giới thiệu các biến bên trong vì()
for (int i = ...; ...; ...) {/ * BAD * /
Đó là C99 hoặc C ++. Mặc dù thực sự sẽ rất tuyệt nếu có điều đó cũng trong C89,
để giới hạn phạm vi của biến vòng lặp, than ôi, chúng ta không thể.
· Trộn con trỏ ký tự có dấu với con trỏ ký tự không dấu
int foo (char * s) {...}
...
char không dấu * t = ...; / * Hoặc U8 * t = ... * /
Bàn Chân); /* TỒI TỆ */
Mặc dù đây là hành vi hợp pháp, nhưng nó chắc chắn là không rõ ràng và ít nhất là gây tử vong
một nền tảng: ví dụ như VMS cc coi đây là một lỗi nghiêm trọng. Một nguyên nhân cho mọi người
thường mắc phải sai lầm này là "naked char" và do đó đề cập đến "naked
con trỏ char "có độ ký không xác định: nó phụ thuộc vào trình biên dịch và các cờ
của trình biên dịch và nền tảng cơ bản cho dù kết quả được ký hay chưa ký.
Cũng vì lý do này mà việc sử dụng 'char' làm chỉ số mảng là không tốt.
· Macro có hằng số chuỗi và các đối số của chúng dưới dạng chuỗi con của chuỗi
không thay đổi
#define FOO (n) printf ("number =% d \ n", n) / * BAD * /
FOO(10);
Ngữ nghĩa trước ANSI cho điều đó tương đương với
printf ("10umber =% d \ 10");
mà có lẽ không phải là những gì bạn mong đợi. Thật không may, ít nhất một hợp lý
trình biên dịch C phổ biến và hiện đại thực hiện "khả năng tương thích ngược thực" ở đây, trong AIX đó là
những gì vẫn xảy ra mặc dù phần còn lại của trình biên dịch AIX rất vui vẻ C89.
· Sử dụng các định dạng printf cho các loại C không cơ bản
IV tôi = ...;
printf ("i =% d \ n", i); /* TỒI TỆ */
Mặc dù điều này có thể tình cờ hoạt động trong một số nền tảng (nơi IV tình cờ là "int"),
nói chung nó không thể. IV có thể là một cái gì đó lớn hơn. Tình hình thậm chí còn tồi tệ hơn với
các loại cụ thể hơn (được xác định bởi bước cấu hình của Perl trong cấu hình.h):
Uid_t ai = ...;
printf ("ai =% d \ n", ai); /* TỒI TỆ */
Vấn đề ở đây là Uid_t có thể không chỉ là "int" -wide mà còn có thể
không dấu, trong trường hợp đó các uid lớn sẽ được in dưới dạng giá trị âm.
Không có giải pháp đơn giản cho điều này vì printf ()trí thông minh có hạn, nhưng
đối với nhiều loại, định dạng phù hợp có sẵn như với hậu tố 'f' hoặc '_f', cho
thí dụ:
IVdf / * IV ở dạng thập phân * /
UVxf / * UV là hệ thập lục phân * /
printf ("i =%" IVdf "\ n", i); / * IVdf là một hằng số chuỗi. * /
Uid_t_f / * Uid_t ở dạng thập phân * /
printf ("ai =%" Uid_t_f "\ n", ai);
Hoặc bạn có thể thử truyền sang loại "đủ rộng":
printf ("i =%" IVdf "\ n", (IV) something_very_small_and_signed);
Cũng nên nhớ rằng định dạng% p thực sự yêu cầu một con trỏ void:
Ư8 * p = ...;
printf ("p =% p \ n", (void *) p);
Tùy chọn gcc "-Wformat" quét các vấn đề như vậy.
· Sử dụng một cách mù quáng các macro đa dạng
gcc đã có chúng trong một thời gian với cú pháp riêng của nó và C99 đã mang chúng với
cú pháp chuẩn hóa. Không sử dụng cái trước và chỉ sử dụng cái sau nếu
HAS_C99_VARIADIC_MACROS được xác định.
· Vượt qua va_list một cách mù quáng
Không phải tất cả các nền tảng đều hỗ trợ chuyển va_list sang các hàm varargs (stdarg) khác. Các
điều phải làm là sao chép va_list bằng cách sử dụng Perl_va_copy () nếu NEED_VA_COPY
được định nghĩa.
· Sử dụng biểu thức câu lệnh gcc
val = ({...; ...; ...}); /* TỒI TỆ */
Mặc dù là một tiện ích mở rộng tốt, nhưng nó không di động. Mã Perl thực sự sử dụng chúng nếu
có sẵn để đạt được một số tốc độ bổ sung (về cơ bản là một dạng nội tuyến thú vị), nhưng bạn
không nên.
· Liên kết một số câu lệnh với nhau trong một macro
Sử dụng macro STMT_START và STMT_END.
STMT_START {
...
} STMT_END
· Kiểm tra hệ điều hành hoặc phiên bản khi nào nên kiểm tra các tính năng
#ifdef __FOONIX__ / * BAD * /
foo = quux ();
#endif
Trừ khi bạn biết chắc chắn 100% rằng quux () chỉ có sẵn cho
Hệ điều hành "Foonix" và cái đó có sẵn và hoạt động chính xác cho tất cả các quá khứ,
hiện tại, và phiên bản tương lai của "Foonix", ở trên là rất sai. Đây là hơn
đúng (mặc dù vẫn chưa hoàn hảo, vì bên dưới là kiểm tra thời gian biên dịch):
#ifdef ĐÃ_QUUX
foo = quux ();
#endif
Làm thế nào để HAS_QUUX được xác định ở vị trí cần thiết? Chà, nếu Foonix xảy ra với
đủ Unixy để có thể chạy tập lệnh Định cấu hình và Cấu hình đã được dạy
về phát hiện và kiểm tra quux (), HAS_QUUX sẽ được xác định chính xác. Trong khác
hy vọng bước cấu hình tương ứng sẽ thực hiện tương tự.
Trong tình huống khó khăn, nếu bạn không thể đợi Định cấu hình để được đào tạo hoặc nếu bạn có
linh cảm về nơi quux () có thể có sẵn, bạn có thể tạm thời thử các cách sau:
#if (đã định nghĩa (__ FOONIX__) || được xác định (__ BARNIX__))
# xác định HAS_QUUX
#endif
...
#ifdef ĐÃ_QUUX
foo = quux ();
#endif
Nhưng trong mọi trường hợp, hãy cố gắng tách biệt các tính năng và hệ điều hành.
· Giả sử nội dung của bộ nhớ tĩnh được trỏ đến bởi các giá trị trả về của Perl
trình bao bọc cho các chức năng thư viện C không thay đổi. Nhiều hàm thư viện C trả về
con trỏ đến bộ nhớ tĩnh có thể được ghi đè bởi các cuộc gọi tiếp theo đến cùng một hoặc
các chức năng liên quan. Perl có các trình bao bọc trọng lượng nhẹ cho một số chức năng này và
mà không tạo bản sao của bộ nhớ tĩnh. Một ví dụ điển hình là giao diện của
các biến môi trường có hiệu lực đối với chương trình. Perl có "PerlEnv_getenv"
để nhận các giá trị từ môi trường. Nhưng kết quả trả về là một con trỏ đến bộ nhớ tĩnh trong
thư viện C. Nếu bạn đang sử dụng giá trị để kiểm tra ngay lập tức một thứ gì đó, thì đó là
tốt, nhưng nếu bạn lưu giá trị và mong muốn nó không thay đổi trong quá trình xử lý sau, bạn
sẽ sai, nhưng có lẽ bạn sẽ không biết vì thư viện C khác nhau
triển khai hoạt động khác nhau và triển khai trên nền tảng bạn đang thử nghiệm
có thể phù hợp với tình huống của bạn. Nhưng trên một số nền tảng, một cuộc gọi tiếp theo tới
"PerlEnv_getenv" hoặc hàm liên quan SẼ ghi đè bộ nhớ mà cuộc gọi đầu tiên của bạn
chỉ tới. Điều này đã dẫn đến một số vấn đề khó gỡ lỗi. Thực hiện "savepv" trong perlapi để
tạo một bản sao, do đó tránh được những vấn đề này. Bạn sẽ phải giải phóng bản sao khi bạn
thực hiện để tránh rò rỉ bộ nhớ. Nếu bạn không kiểm soát được thời điểm nó được giải phóng, bạn sẽ
cần tạo bản sao ở dạng vô hướng sinh tử, như sau:
if ((s = PerlEnv_getenv ("foo") == NULL) {
... / * xử lý trường hợp NULL * /
}
khác {
s = SvPVX (sv_2mortal (newSVpv (s, 0)));
}
Ví dụ trên chỉ hoạt động nếu "s" được kết thúc bằng "NUL"; nếu không bạn phải vượt qua
độ dài của nó thành "newSVpv".
Có vấn đề WELFARE Giao diện
· malloc(0) phân bổ tài chính(0), calloc (0, 0) là không di động. Được phân bổ di động tại
ít nhất một byte. (Nói chung, bạn hiếm khi cần phải làm việc ở mức thấp này, nhưng
thay vào đó sử dụng các trình bao bọc malloc khác nhau.)
· snprintf () - kiểu trả về là không thể chuyển được. Sử dụng my_snprintf () thay thế.
Bảo mật vấn đề
Cuối cùng nhưng không kém phần quan trọng, đây là các mẹo khác nhau để viết mã an toàn hơn. Xem thêm perlclib cho
libc / stdio thay thế một người nên sử dụng.
· Không được dùng được()
Hoặc chúng tôi sẽ công khai chế giễu bạn. Nghiêm túc.
· Không được dùng tmpfile ()
Sử dụng mkstemp () thay thế.
· Không được dùng strcpy () or strcat () or strncpy () or strncat ()
Sử dụng my_strlcpy () và my_strlcat () thay vào đó: họ sử dụng triển khai gốc,
hoặc triển khai riêng của Perl (mượn từ triển khai miền công cộng của INN).
· Không được dùng sprintf () or vsprintf ()
Nếu bạn thực sự chỉ muốn chuỗi byte đơn giản, hãy sử dụng my_snprintf () và my_vsnprintf ()
thay vào đó, sẽ cố gắng sử dụng snprintf () và vsnprintf () nếu những API an toàn hơn
có sẵn. Nếu bạn muốn thứ gì đó đẹp hơn một chuỗi byte đơn thuần, hãy sử dụng "Perl_form" ()
hoặc SV và "Perl_sv_catpvf ()".
Lưu ý rằng glibc "printf ()", "sprintf ()", v.v. có lỗi trước phiên bản glibc 2.17.
Họ sẽ không cho phép định dạng "% .s" có độ chính xác để tạo chuỗi không hợp lệ
UTF-8 nếu ngôn ngữ cơ bản hiện tại của chương trình là UTF-8. Điều gì xảy ra là vậy
% s và toán hạng của nó đơn giản bị bỏ qua mà không có bất kỳ thông báo nào.
.
· Không được dùng atoi ()
Sử dụng grok_atoUV () thay thế. atoi () có hành vi không được xác định rõ trên các tràn và không thể
được sử dụng để phân tích cú pháp gia tăng. Nó cũng bị ảnh hưởng bởi ngôn ngữ, điều này thật tệ.
· Không được dùng strtol () or strtoul ()
Sử dụng grok_atoUV () thay thế. strtol () or strtoul () (hoặc macro thân thiện với IV / UV của chúng
cải trang, Strtol () và Strtoul (), hoặc là Atol () và Atoul () bị ảnh hưởng bởi ngôn ngữ,
là xấu.
NỢ
Bạn có thể biên dịch một phiên bản gỡ lỗi đặc biệt của Perl, cho phép bạn sử dụng "-D"
tùy chọn của Perl để cho biết thêm về những gì Perl đang làm. Nhưng đôi khi không có
thay vì đi sâu vào với trình gỡ lỗi, hoặc để xem dấu vết ngăn xếp của một kết xuất lõi
(rất hữu ích trong một báo cáo lỗi), hoặc cố gắng tìm ra điều gì đã xảy ra trước phần lõi
kết quả đã xảy ra, hoặc làm thế nào chúng tôi có kết quả sai hoặc không mong muốn.
poking at Perl
Để thực sự khám phá Perl, có thể bạn sẽ muốn xây dựng Perl để gỡ lỗi, như
điều này:
./Configure -d -D tối ưu hóa = -g
làm cho
"-g" là một cờ đối với trình biên dịch C để nó tạo ra thông tin gỡ lỗi sẽ cho phép
chúng ta bước qua một chương trình đang chạy và để xem chúng ta đang ở hàm C nào (không có
thông tin gỡ lỗi mà chúng ta có thể chỉ thấy các địa chỉ số của các hàm,
mà không phải là rất hữu ích).
Thiết lập cũng sẽ bật biểu tượng biên dịch "GỠ LỖI" cho phép tất cả
mã gỡ lỗi nội bộ trong Perl. Có rất nhiều thứ bạn có thể gỡ lỗi
this: perlrun liệt kê tất cả chúng và cách tốt nhất để tìm hiểu về chúng là chơi về
với họ. Các tùy chọn hữu ích nhất có lẽ là
l Xử lý ngăn xếp theo ngữ cảnh (vòng lặp)
t Thực hiện theo dõi
o Phương pháp và giải quyết quá tải
c Chuyển đổi chuỗi / số
Một số chức năng của mã gỡ lỗi có thể đạt được bằng cách sử dụng mô-đun XS.
-Dr => sử dụng re 'debug'
-Dx => sử dụng O 'Debug'
Sử dụng a cấp nguồn trình sửa lỗi
Nếu đầu ra gỡ lỗi của "-D" không giúp được bạn, thì đã đến lúc chuyển qua perl's
thực thi với trình gỡ lỗi cấp nguồn.
· Chúng tôi sẽ sử dụng "gdb" cho các ví dụ của chúng tôi ở đây; các nguyên tắc sẽ áp dụng cho bất kỳ trình gỡ lỗi nào (nhiều
nhà cung cấp gọi trình gỡ lỗi của họ là "dbx"), nhưng hãy kiểm tra hướng dẫn sử dụng của trình bạn đang sử dụng.
Để kích hoạt trình gỡ lỗi, hãy nhập
gdb ./perl
Hoặc nếu bạn có một kết xuất lõi:
gdb ./perl lõi
Bạn sẽ muốn làm điều đó trong cây nguồn Perl của mình để trình gỡ lỗi có thể đọc mã nguồn.
Bạn sẽ thấy thông báo bản quyền, theo sau là lời nhắc.
(Gdb)
"help" sẽ đưa bạn vào tài liệu, nhưng đây là các lệnh hữu ích nhất:
· Chạy [args]
Chạy chương trình với các đối số đã cho.
· Break function_name
· Ngắt nguồn.c: xxx
Cho trình gỡ lỗi biết rằng chúng tôi sẽ muốn tạm dừng thực thi khi chúng tôi đến được
chức năng (nhưng xem "Các chức năng nội bộ" trong perlguts!) hoặc dòng đã cho trong tên
tập tin nguồn.
· bươc
Bước qua chương trình một dòng tại một thời điểm.
· tiếp theo
Bước qua chương trình một dòng tại một thời điểm, mà không giảm xuống các hàm.
· tiếp tục
Chạy cho đến điểm ngắt tiếp theo.
· hoàn thành
Chạy cho đến khi kết thúc chức năng hiện tại, sau đó dừng lại.
· 'đi vào'
Chỉ cần nhấn Enter sẽ thực hiện lại thao tác gần đây nhất - thật may mắn khi
bước qua hàng dặm mã nguồn.
· Ptype
In định nghĩa C của đối số đã cho.
(gdb) ptype PL_op
loại = cấu trúc op {
OP * op_next;
OP * op_sibparent;
OP * (* op_ppaddr) (void);
PADOFFSET op_targ;
unsigned int op_type: 9;
unsigned int op_opt: 1;
unsigned int op_slabbed: 1;
unsigned int op_savefree: 1;
unsigned int op_static: 1;
unsigned int op_folded: 1;
unsigned int op_spare: 2;
Op_flags U8;
U8 op_riêng;
} *
· in
Thực thi mã C đã cho và in kết quả của nó. CẢNH BÁO: Perl sử dụng nhiều
macro và gdb không nhất thiết phải hỗ trợ macro (xem phần sau "hỗ trợ macro gdb").
Bạn sẽ phải tự thay thế chúng hoặc gọi cpp trên các tệp mã nguồn (xem
"Mục tiêu .i") Vì vậy, chẳng hạn, bạn không thể nói
in SvPV_nolen (sv)
nhưng bạn phải nói
print Perl_sv_2pv_nolen (sv)
Bạn có thể thấy hữu ích khi có một "từ điển macro", bạn có thể tạo ra bằng cách nói "cpp
-dM perl.c | sắp xếp ". Ngay cả khi đó, cpp sẽ không áp dụng đệ quy các macro đó cho bạn.
gdb vĩ mô hỗ trợ
Các phiên bản gần đây của gdb có hỗ trợ macro khá tốt, nhưng để sử dụng nó, bạn sẽ cần
để biên dịch perl với các định nghĩa macro có trong thông tin gỡ lỗi. Sử dụng gcc
phiên bản 3.1, điều này có nghĩa là cấu hình với "-Doptimize = -g3". Các trình biên dịch khác có thể sử dụng
chuyển đổi khác nhau (nếu chúng hỗ trợ macro gỡ lỗi).
Bán phá giá Perl Ngày Cấu trúc
Một cách để vượt qua địa ngục vĩ mô này là sử dụng các hàm kết xuất trong đổ.c; những cái này
hoạt động giống như một Devel nội bộ :: Peek, nhưng chúng cũng bao gồm các OP và các cấu trúc khác
mà bạn không thể nhận được từ Perl. Hãy lấy một ví dụ. Chúng tôi sẽ sử dụng "$ a = $ b + $ c" chúng tôi
được sử dụng trước đây, nhưng hãy cung cấp cho nó một chút ngữ cảnh: "$ b =" 6XXXX "; $ c = 2.3;". Tốt ở đâu
nơi để dừng lại và xung quanh?
Còn về "pp_add", hàm chúng ta đã kiểm tra trước đó để triển khai toán tử "+":
(gdb) ngắt Perl_pp_add
Điểm ngắt 1 tại 0x46249f: tệp pp_hot.c, dòng 309.
Lưu ý rằng chúng tôi sử dụng "Perl_pp_add" chứ không phải "pp_add" - xem "Các chức năng nội bộ" trong perlguts. Với
điểm ngắt tại chỗ, chúng ta có thể chạy chương trình của mình:
(gdb) run -e '$ b = "6XXXX"; $ c = 2.3; $ a = $ b + $ c '
Rất nhiều rác sẽ trôi qua khi gdb đọc trong các thư viện và tệp nguồn có liên quan, và
sau đó:
Điểm ngắt 1, Perl_pp_add () tại pp_hot.c: 309
309 dSP; DATARGET; tryAMAGICbin (thêm, opASSIGN);
(gdb) bước
311 dPOPTOPnnrl_ul;
(Gdb)
Chúng tôi đã xem xét đoạn mã này trước đây và chúng tôi nói rằng "dPOPTOPnnrl_ul" sắp xếp cho hai
"NV" sẽ được đặt thành "left" và "right" - hãy mở rộng một chút:
#define dPOPTOPnnrl_ul NV phải = POPn; \
SV * leftsv = TOPs; \
NV còn lại = USE_LEFT (leftsv)? SvNV (leftsv): 0.0
"POPn" lấy SV từ trên cùng của ngăn xếp và lấy trực tiếp NV của nó (nếu
"SvNOK" được đặt) hoặc bằng cách gọi hàm "sv_2nv". "TOP" lấy SV tiếp theo từ
trên cùng của ngăn xếp - có, "POPn" sử dụng "TOP" - nhưng không xóa nó. Sau đó, chúng tôi sử dụng "SvNV" để
lấy NV từ "leftsv" theo cách giống như trước đây - vâng, "POPn" sử dụng "SvNV".
Vì chúng tôi không có NV cho $ b, chúng tôi sẽ phải sử dụng "sv_2nv" để chuyển đổi nó. Nếu chúng ta bước
một lần nữa, chúng ta sẽ thấy mình ở đó:
(gdb) bước
Perl_sv_2nv (sv = 0xa0675d0) tại sv.c: 1669
1669 nếu (! Sv)
(Gdb)
Giờ đây, chúng tôi có thể sử dụng "Perl_sv_dump" để điều tra SV:
(gdb) in Perl_sv_dump (sv)
SV = PV(0xa057cc0) at 0xa0675d0
LẠI LẠI = 1
CỜ = (POK, pPOK)
PV = 0xa06a510 "6XXXX" \ 0
hiện tại = 5
Len = 6
$ 1 = vô hiệu
Chúng tôi biết chúng tôi sẽ nhận được 6 từ điều này, vì vậy hãy hoàn thành chương trình con:
(gdb) kết thúc
Chạy cho đến khi thoát khỏi # 0 Perl_sv_2nv (sv = 0xa0675d0) tại sv.c: 1671
0x462669 trong Perl_pp_add () tại pp_hot.c: 311
311 dPOPTOPnnrl_ul;
Chúng tôi cũng có thể loại bỏ tùy chọn này: tùy chọn hiện tại luôn được lưu trữ trong "PL_op" và chúng tôi có thể kết xuất
nó với "Perl_op_dump". Điều này sẽ cung cấp cho chúng ta kết quả tương tự như B :: Debug.
(gdb) in Perl_op_dump (PL_op)
{
13 TYPE = thêm ===> 14
MỤC TIÊU = 1
FLAGS = (SCALAR, KIDS)
{
TYPE = null ===> (12)
(là rv2sv)
FLAGS = (SCALAR, KIDS)
{
11 TYPE = gvsv ===> 12
CỜ = (SCALAR)
GV = main :: b
}
}
# hoàn thành việc này sau #
Sử dụng gdb đến xem at riêng các bộ phận of a chương trình
Với ví dụ trên, bạn đã biết tìm kiếm "Perl_pp_add", nhưng nếu có
nhiều cuộc gọi đến nó ở khắp nơi hoặc bạn không biết bạn là ai
tìm kiếm?
Một cách để làm điều này là thực hiện một cuộc gọi hiếm hoi ở đâu đó gần nơi bạn đang tìm kiếm. Vì
ví dụ, bạn có thể thêm "nghiên cứu" trước phương pháp của mình:
nghiên cứu;
Và trong gdb làm:
(gdb) ngắt Perl_pp_study
Và sau đó bước cho đến khi bạn đạt được những gì bạn đang tìm kiếm. Điều này hoạt động tốt trong một vòng lặp nếu bạn
muốn chỉ ngắt ở một số lần lặp lại nhất định:
cho $ c (1..100) {của tôi
nghiên cứu nếu $ c == 50;
}
Sử dụng gdb đến xem at gì các phân tích cú pháp / lexer đang làm
Nếu bạn muốn xem perl đang làm gì khi phân tích / ghép nối mã của mình, bạn có thể sử dụng "BEGIN
{} ":
print "Trước \ n";
BEGIN {học tập; }
print "Sau \ n";
Và trong gdb:
(gdb) ngắt Perl_pp_study
Nếu bạn muốn xem trình phân tích cú pháp / lexer đang làm gì bên trong các khối "if" và những thứ tương tự như bạn
cần phải phức tạp hơn một chút:
if ($ a && $ b && do {BEGIN {study} 1} && $ c) {...}
SOURCE MÃ THỐNG KÊ PHÂN TÍCH
Có nhiều công cụ khác nhau để phân tích mã nguồn C tĩnh lặng, như trái ngược với năng động,
nghĩa là, mà không cần thực thi mã. Có thể phát hiện rò rỉ tài nguyên, không xác định
hành vi, loại không khớp, vấn đề về tính di động, đường dẫn mã có thể gây ra bất hợp pháp
truy cập bộ nhớ và các vấn đề tương tự khác bằng cách phân tích cú pháp mã C và xem
biểu đồ kết quả, nó cho biết gì về việc thực thi và các luồng dữ liệu. Như một vấn đề của
thực tế, đây chính xác là cách trình biên dịch C biết để đưa ra cảnh báo về mã không rõ ràng.
xơ vải, nẹp
Trình kiểm tra chất lượng mã C cũ tốt, "lint", có sẵn ở một số nền tảng, nhưng
xin lưu ý rằng có một số cách triển khai khác nhau của nó bằng cách khác nhau
nhà cung cấp, có nghĩa là các cờ không giống nhau trên các nền tảng khác nhau.
Có một biến thể xơ vải được gọi là "nẹp" (Dây buộc lập trình an toàn) có sẵn từ
http://www.splint.org/ sẽ biên dịch trên bất kỳ nền tảng giống Unix nào.
Có "lint" và mục tiêu trong Makefile, nhưng bạn có thể phải làm việc với
cờ (xem ở trên).
độ che phủ
Độ che phủ (http://www.coverity.com/) là một sản phẩm tương tự như xơ vải và như một vật thử nghiệm cho
sản phẩm của họ, họ kiểm tra định kỳ một số dự án nguồn mở và họ đưa ra
tài khoản cho các nhà phát triển nguồn mở đối với cơ sở dữ liệu khiếm khuyết.
cpd (cắt và dán máy dò)
Công cụ cpd phát hiện mã hóa cắt và dán. Nếu một trường hợp của mã cắt và dán
thay đổi, tất cả các điểm khác có lẽ cũng nên được thay đổi. Do đó mã như vậy nên
có thể được biến thành một chương trình con hoặc một macro.
cpd (http://pmd.sourceforge.net/cpd.html) là một phần của dự án pmd
(http://pmd.sourceforge.net/). pmd ban đầu được viết để phân tích tĩnh của Java
mã, nhưng sau đó phần cpd của nó được mở rộng để phân tích cú pháp C và C ++.
Tải xuống pmd-bin-XYzip () từ trang SourceForge, giải nén pmd-XYjar từ
nó, và sau đó chạy nó trên mã nguồn do đó:
java -cp pmd-XYjar net.sourceforge.pmd.cpd.CPD \
--minimum-tokens 100 --files / some / where / src --language c> cpd.txt
Bạn có thể gặp phải giới hạn bộ nhớ, trong trường hợp đó, bạn nên sử dụng tùy chọn -Xmx:
Java-Xmx512M ...
gcc cảnh báo
Mặc dù có thể viết nhiều về sự không nhất quán và các vấn đề liên quan đến cảnh báo gcc
(như "-Wall" không có nghĩa là "tất cả các cảnh báo" hoặc một số vấn đề về tính di động phổ biến không
bị bao phủ bởi "-Wall" hoặc "-ansi" và "-pedantic" đều là một định nghĩa kém
thu thập các cảnh báo, v.v.), gcc vẫn là một công cụ hữu ích trong việc giữ mã hóa của chúng tôi
mũi sạch sẽ.
"-Wall" được bật theo mặc định.
"-Ansi" (và thẻ phụ của nó, "-pedantic") sẽ rất tốt nếu luôn được bật, nhưng
rất tiếc là chúng không an toàn trên tất cả các nền tảng, chẳng hạn như chúng có thể gây tử vong
xung đột với tiêu đề hệ thống (Solaris là một ví dụ điển hình). Nếu cấu hình
"-Dgccansipedantic" được sử dụng, giao diện người dùng "cflags" chọn "-ansi -pedantic" cho
nền tảng mà chúng được biết là an toàn.
Bắt đầu từ Perl 5.9.4, các cờ bổ sung sau được thêm vào:
· "-Wendif-label"
· "-Wextra"
· "-Khai báo-sau-tuyên bố"
Những lá cờ sau sẽ rất tuyệt nếu có nhưng trước tiên chúng cần có Augean của riêng mình
quản trị viên ổn định:
· "-Wpointer-arith"
· "-Wshadow"
· "-Nguyên mẫu"
"-Điều kiện" là một ví dụ khác cho thấy xu hướng khó chịu của gcc là gói rất nhiều
cảnh báo dưới một công tắc (sẽ không thể triển khai trong thực tế vì nó sẽ
phàn nàn rất nhiều) nhưng nó có chứa một số cảnh báo sẽ có lợi nếu có
khả dụng của riêng chúng, chẳng hạn như cảnh báo về hằng số chuỗi bên trong macro
có chứa các đối số macro: điều này hoạt động trước ANSI khác với trong ANSI,
và một số trình biên dịch C vẫn đang trong quá trình chuyển đổi, AIX là một ví dụ.
Cảnh báo of khác C trình biên dịch
Các trình biên dịch C khác (vâng, có đang các trình biên dịch C khác với gcc) thường có "nghiêm ngặt
Bật chế độ ANSI "hoặc" nghiêm ngặt ANSI với một số tiện ích mở rộng khả năng di chuyển ", chẳng hạn như Mặt trời
Workshop có chế độ "-Xa" được bật (mặc dù ngầm), hoặc DEC (những ngày này, HP ...) có
Chế độ "-std1" đang bật.
NHỚ NGƯỜI NỢ
LƯU Ý 1: Chạy dưới các trình gỡ lỗi bộ nhớ cũ hơn như Purify, valgrind hoặc Third Degree
làm chậm quá trình thực thi rất nhiều: giây trở thành phút, phút trở thành giờ. Vì
ví dụ như Perl 5.8.1, ext / Encode / t / Unicode.t mất nhiều thời gian để
hoàn thành ví dụ như Purify, Third Degree, và valgrind. Theo giá trị, nó mất nhiều hơn
sáu giờ, ngay cả trên một máy tính linh hoạt. Bài kiểm tra đã nói phải làm một cái gì đó khá
không thân thiện với trình gỡ lỗi bộ nhớ. Nếu bạn không cảm thấy muốn chờ đợi, bạn có thể chỉ cần giết
đi quá trình perl. Hầu như valgrind làm chậm quá trình thực thi theo hệ số 10,
AddressSanitizer theo hệ số 2.
LƯU Ý 2: Để giảm thiểu số lượng cảnh báo sai rò rỉ bộ nhớ (xem "PERL_DESTRUCT_LEVEL" để biết
thông tin thêm), bạn phải đặt biến môi trường PERL_DESTRUCT_LEVEL thành 2. Đối với
ví dụ, như thế này:
vi PERL_DESTRUCT_LEVEL = 2 valgrind ./perl -Ilib ...
LƯU Ý 3: Có những rò rỉ bộ nhớ đã biết khi có lỗi thời gian biên dịch trong eval hoặc
yêu cầu, nhìn thấy "S_doeval" trong ngăn xếp cuộc gọi là một dấu hiệu tốt về những điều này. Khắc phục những rò rỉ này
là không tầm thường, không may, nhưng chúng phải được sửa chữa cuối cùng.
LƯU Ý 4: DynaLoader sẽ không tự dọn dẹp hoàn toàn trừ khi Perl được xây dựng với
Định cấu hình tùy chọn "-Accflags = -DDL_UNLOAD_ALL_AT_EXIT".
valgrind
Công cụ valgrind có thể được sử dụng để tìm ra cả rò rỉ bộ nhớ và bộ nhớ heap bất hợp pháp
quyền truy cập. Kể từ phiên bản 3.3.0, Valgrind chỉ hỗ trợ Linux trên x86, x86-64 và PowerPC
và Darwin (OS X) trên x86 và x86-64). Mục tiêu "test.valgrind" đặc biệt có thể được sử dụng để
chạy các bài kiểm tra dưới valgrind. Đã tìm thấy lỗi và rò rỉ bộ nhớ được đăng nhập vào các tệp có tên
testfile.valgrind và theo mặc định đầu ra được hiển thị nội dòng.
Ví dụ sử dụng:
thực hiện test.valgrind
Vì valgrind thêm chi phí đáng kể, các thử nghiệm sẽ mất nhiều thời gian hơn để chạy. Các
Hỗ trợ thử nghiệm valgrind đang được chạy song song để giúp thực hiện điều này:
TEST_JOBS = 9 thực hiện test.valgrind
Lưu ý rằng hai lời gọi trên sẽ rất dài dòng vì bộ nhớ có thể truy cập và bị rò rỉ-
kiểm tra được bật theo mặc định. Nếu bạn chỉ muốn xem các lỗi thuần túy, hãy thử:
VG_OPTS = '- q --leak-check = no --show-Reahable = no' TEST_JOBS = 9 \
thực hiện test.valgrind
Valgrind cũng cung cấp một công cụ cachegrind, được gọi trên perl là:
VG_OPTS = - tool = cachegrind make test.valgrind
Vì các thư viện hệ thống (đáng chú ý nhất là glibc) cũng gây ra lỗi, valgrind cho phép
ngăn chặn các lỗi như vậy bằng cách sử dụng các tệp nén. Tệp ngăn chặn mặc định đi kèm
với valgrind đã bắt được rất nhiều người trong số họ. Một số ngăn chặn bổ sung được xác định trong
t / perl.supp.
Để nhận được giá trị và để biết thêm thông tin, hãy xem
http://valgrind.org/
Địa chỉSanitizer
AddressSanitizer là một phần mở rộng clang và gcc, được bao gồm trong clang kể từ v3.1 và gcc kể từ
v4.8. Nó kiểm tra con trỏ heap bất hợp pháp, con trỏ toàn cục, con trỏ ngăn xếp và sử dụng sau khi miễn phí
lỗi và đủ nhanh để bạn có thể dễ dàng biên dịch việc gỡ lỗi hoặc tối ưu hóa perl của mình
với nó. Nó không kiểm tra rò rỉ bộ nhớ mặc dù. AddressSanitizer có sẵn cho Linux,
Mac OS X và sắp có trên Windows.
Để xây dựng perl với AddressSanitizer, lệnh gọi Cấu hình của bạn sẽ giống như sau:
sh Định cấu hình -des -Dcc = clang \
-Accflags = -faddress-sanitizer -Aldflags = -faddress-sanitizer \
-Alddlflags = -shared \ -faddress-sanitizer
trong đó các đối số này có nghĩa là:
· -Dcc = clang
Điều này sẽ được thay thế bằng đường dẫn đầy đủ đến tệp thực thi clang của bạn nếu nó không có trong
con đường.
· -Accflags = -faddress-sanitizer
Biên dịch các nguồn perl và phần mở rộng với AddressSanitizer.
· -Aldflags = -faddress-sanitizer
Liên kết tệp thực thi perl với AddressSanitizer.
· -Alddlflags = -shared \ -faddress-sanitizer
Liên kết các tiện ích mở rộng động với AddressSanitizer. Bạn phải chỉ định "được chia sẻ" theo cách thủ công
bởi vì việc sử dụng "-Alddlflags = -shared" sẽ ngăn không cho Định cấu hình đặt giá trị mặc định
giá trị cho "lddlflags", thường chứa "-shared" (ít nhất là trên Linux).
Xem thêmhttp://code.google.com/p/address-sanitizer/wiki/AddressSanitizer>.
SƠ LƯỢC
Tùy thuộc vào nền tảng của bạn, có nhiều cách khác nhau để lập hồ sơ Perl.
Có hai kỹ thuật thường được sử dụng để lập hồ sơ thực thi: thống kê lấy mẫu thời gian
và khối cơ bản hơn nữa.
Phương pháp đầu tiên lấy mẫu định kỳ của bộ đếm chương trình CPU, và vì
bộ đếm chương trình có thể được tương quan với mã được tạo cho các chức năng, chúng tôi nhận được
chế độ xem thống kê về các chức năng mà chương trình đang sử dụng. Những lưu ý là
rằng các chức năng rất nhỏ / nhanh có xác suất hiển thị trong hồ sơ thấp hơn và
định kỳ làm gián đoạn chương trình (điều này thường được thực hiện khá thường xuyên, trong
quy mô mili giây) áp đặt chi phí bổ sung có thể làm sai lệch kết quả. Các
vấn đề đầu tiên có thể được giảm bớt bằng cách chạy mã lâu hơn (nói chung đây là một
ý tưởng để lập hồ sơ), vấn đề thứ hai thường được đề phòng bởi các công cụ lập hồ sơ
chính họ.
Phương pháp thứ hai chia mã được tạo thành cơ bản khối. Các khối cơ bản là
phần mã chỉ được nhập ở phần đầu và chỉ được thoát ra ở phần cuối. Vì
ví dụ, một bước nhảy có điều kiện bắt đầu một khối cơ bản. Cấu hình khối cơ bản thường hoạt động bằng cách
dụng cụ mã bằng cách thêm nhập cơ bản chặn #nnnn mã giữ sách cho
mã được tạo. Trong quá trình thực thi mã, các bộ đếm khối cơ bản sau đó
được cập nhật một cách thích hợp. Lưu ý là mã bổ sung được thêm vào có thể làm sai lệch kết quả:
một lần nữa, các công cụ lập hồ sơ thường cố gắng tính hiệu ứng của chính chúng ra khỏi kết quả.
gprof Hồ sơ
gprof là một công cụ cấu hình có sẵn trong nhiều nền tảng Unix sử dụng thống kê thời gian-
lấy mẫu. Bạn có thể tạo một phiên bản cấu hình của perl bằng cách biên dịch bằng cách sử dụng gcc với cờ
"-pg". Chỉnh sửa config.sh hoặc chạy lại Thiết lập. Chạy phiên bản cấu hình của Perl
sẽ tạo một tệp đầu ra có tên là gmon.out trong đó chứa dữ liệu hồ sơ được thu thập
trong quá trình thực hiện.
gợi ý nhanh:
$ sh Định cấu hình -des -Dusedevel -Accflags = '- pg' \
-Aldflags = '- pg' -Alddlflags = '- pg -shared' \
&& làm perl
$ ./perl ... # tạo gmon.out trong thư mục hiện tại
$ gprof ./perl> hết
bớt $ ra
(bạn có thể cần thêm "-shared" vào dòng <-Alddlflags> cho đến khi RT # 118199 là
đã giải quyết)
Sản phẩm gprof sau đó công cụ có thể hiển thị dữ liệu đã thu thập theo nhiều cách khác nhau. Thường xuyên gprof
hiểu các tùy chọn sau:
· -Một
Loại bỏ các chức năng được xác định tĩnh khỏi cấu hình.
· -NS
Loại bỏ các mô tả dài dòng trong hồ sơ.
· -E thói quen
Loại trừ quy trình đã cho và quy trình hậu duệ của nó khỏi hồ sơ.
· -F thói quen
Chỉ hiển thị quy trình đã cho và con cháu của nó trong hồ sơ.
· -NS
Tạo một tệp tóm tắt có tên gmon.sum sau đó có thể được trao cho gprof tiếp theo
chạy để tích lũy dữ liệu qua nhiều lần chạy.
· -Z
Hiển thị các quy trình không sử dụng.
Để biết giải thích chi tiết hơn về các lệnh có sẵn và định dạng đầu ra, hãy xem
tài liệu địa phương của gprof.
GCC gcov Hồ sơ
cơ bản chặn profiling chính thức có sẵn trong gcc 3.0 trở lên. Bạn có thể xây dựng một
phiên bản hồ sơ của perl bằng cách biên dịch bằng cách sử dụng gcc với các cờ "-fprofile-arcs
-sao-phủ-sóng ". Có thể chỉnh sửa config.sh hoặc chạy lại Thiết lập.
gợi ý nhanh:
$ sh Định cấu hình -des -Dusedevel -Doptimize = '- g' \
-Accflags = '- fprofile-arcs -ftest-cover' \
-Aldflags = '- fprofile-arcs -ftest-cover' \
-Alddlflags = '- fprofile-arcs -ftest-cover -shared' \
&& làm perl
$ rm -f biểu thức chính quy.c.gcov biểu thức chính quy.gcda
$ ./perl ...
$ gcov regrec.c
$ bớt regexec.c.gcov
(bạn có thể cần thêm "-shared" vào dòng <-Alddlflags> cho đến khi RT # 118199 là
đã giải quyết)
Chạy phiên bản cấu hình của Perl sẽ tạo ra đầu ra cấu hình. Cho mỗi
tập tin nguồn đi kèm .gcda tệp sẽ được tạo.
Để hiển thị kết quả, bạn sử dụng gcov tiện ích (nên được cài đặt nếu bạn có gcc
3.0 hoặc mới hơn được cài đặt). gcov được chạy trên các tệp mã nguồn, như thế này
gcov sv.c
điều gì sẽ gây ra sv.c.gcov được tạo ra. Các .gcov tệp chứa mã nguồn
được chú thích với tần số thực thi tương đối được chỉ ra bằng dấu "#". Nếu bạn muốn
tạo ra .gcov cho tất cả các tệp đối tượng cấu hình, bạn có thể chạy một cái gì đó như sau:
cho tệp trong `tìm. -name \ *. gcno`
do sh -c "cd` dirname $ file` && gcov `basename $ file .gcno`"
thực hiện
Các tùy chọn hữu ích của gcov bao gồm "-b" sẽ tóm tắt khối cơ bản, nhánh và
phạm vi cuộc gọi chức năng và "-c" thay vì tần số tương đối sẽ sử dụng
số đếm. Để biết thêm thông tin về việc sử dụng gcov và cấu hình khối cơ bản với gcc, xem
sổ tay GNU CC mới nhất. Kể từ gcc 4.8, đây là lúc
<http://gcc.gnu.org/onlinedocs/gcc/Gcov-Intro.html# Gcov-Intro>
KHÁC NHANH
PERL_DESTRUCT_LEVEL
Nếu bạn muốn tự chạy bất kỳ bài kiểm tra nào theo cách thủ công bằng cách sử dụng ví dụ: valgrind, vui lòng lưu ý
điều đó theo mặc định perl làm không dọn dẹp rõ ràng tất cả bộ nhớ mà nó đã cấp phát (chẳng hạn như
đấu trường bộ nhớ toàn cầu) nhưng thay vào đó cho phép lối ra() của toàn bộ chương trình "chăm sóc" như vậy
phân bổ, còn được gọi là "sự phá hủy toàn cầu của các đối tượng".
Có một cách để yêu cầu perl thực hiện dọn dẹp hoàn toàn: đặt biến môi trường
PERL_DESTRUCT_LEVEL thành một giá trị khác 2. Trình bao bọc t / TEST không đặt giá trị này thành XNUMX và điều này
là những gì bạn cũng cần làm, nếu bạn không muốn thấy "rò rỉ toàn cầu": Ví dụ:
chạy theo valgrind
vi PERL_DESTRUCT_LEVEL = 2 valgrind ./perl -Ilib t / foo / bar.t
(Lưu ý: mô-đun mod_perl apache cũng sử dụng biến môi trường này cho các mục đích riêng của nó
và mở rộng ngữ nghĩa của nó. Tham khảo tài liệu mod_perl để biết thêm thông tin.
Ngoài ra, các chủ đề được tạo ra thực hiện tương đương với việc đặt biến này thành giá trị 1.)
Nếu, khi kết thúc cuộc chạy, bạn nhận được thông báo N vô hướng bị rò rỉ, bạn có thể biên dịch lại với
"-DDEBUG_LEAKING_SCALARS", sẽ làm cho địa chỉ của tất cả các SV bị rò rỉ đó là
được đưa ra cùng với các chi tiết về nơi mỗi SV được cấp phát ban đầu. Thông tin này
cũng được hiển thị bởi Devel :: Peek. Lưu ý rằng các chi tiết bổ sung được ghi lại với mỗi SV
làm tăng mức sử dụng bộ nhớ, vì vậy nó không nên được sử dụng trong môi trường sản xuất. Nó cũng
chuyển đổi "new_SV ()" từ macro thành một hàm thực, vì vậy bạn có thể sử dụng
trình gỡ lỗi để khám phá nơi các SV khó chịu đó đã được phân bổ.
Nếu bạn thấy rằng bạn đang rò rỉ bộ nhớ trong thời gian chạy, nhưng không có giá trị hoặc
"-DDEBUG_LEAKING_SCALARS" sẽ tìm thấy bất kỳ thứ gì, có thể bạn đang rò rỉ các SV vẫn còn
có thể truy cập được và sẽ được làm sạch đúng cách trong quá trình tiêu hủy trình thông dịch. Trong như vậy
trường hợp, sử dụng công tắc "-Dm" có thể chỉ cho bạn nguồn rò rỉ. Nếu tệp thực thi
được xây dựng với "-DDEBUG_LEAKING_SCALARS", "-Dm" sẽ xuất ra phân bổ SV ngoài
cấp phát bộ nhớ. Mỗi phân bổ SV có một số sê-ri riêng biệt sẽ được ghi
về sự tạo ra và tiêu diệt SV. Vì vậy, nếu bạn đang thực thi mã rò rỉ trong một vòng lặp,
bạn cần tìm các SV được tạo nhưng chưa bao giờ bị phá hủy giữa mỗi chu kỳ. Nếu như
một SV như vậy được tìm thấy, hãy đặt điểm ngắt có điều kiện trong "new_SV ()" và chỉ đặt điểm ngắt
khi "PL_sv_serial" bằng số sê-ri của SV bị rò rỉ. Sau đó, bạn sẽ bắt
trình thông dịch ở chính xác trạng thái nơi SV bị rò rỉ được cấp phát, đó là
trong nhiều trường hợp đủ để tìm ra nguồn rò rỉ.
Vì "-Dm" đang sử dụng lớp PerlIO cho đầu ra, bản thân nó sẽ phân bổ khá nhiều
SV, được ẩn để tránh đệ quy. Bạn có thể bỏ qua lớp PerlIO nếu bạn sử dụng
Thay vào đó, nhật ký SV được cung cấp bởi "-DPERL_MEM_LOG".
PERL_MEM_LOG
Nếu được biên dịch bằng "-DPERL_MEM_LOG", cả cấp phát bộ nhớ và SV đều trải qua quá trình ghi nhật ký
, rất tiện lợi cho việc thiết lập điểm ngắt.
Trừ khi "-DPERL_MEM_LOG_NOIMPL" cũng được biên dịch, các chức năng ghi nhật ký sẽ đọc
$ ENV {PERL_MEM_LOG} để xác định xem có ghi lại sự kiện hay không và nếu có thì làm như thế nào:
$ ENV {PERL_MEM_LOG} = ~ / m / Ghi nhật ký tất cả các hoạt động bộ nhớ
$ ENV {PERL_MEM_LOG} = ~ / s / Ghi nhật ký tất cả các hoạt động SV
$ ENV {PERL_MEM_LOG} = ~ / t / bao gồm dấu thời gian trong Nhật ký
$ ENV {PERL_MEM_LOG} = ~ / ^ (\ d +) / ghi vào FD đã cho (mặc định là 2)
Ghi nhật ký bộ nhớ tương tự như "-Dm" nhưng độc lập với "-DDEBUGGING", và ở
mức cao hơn; tất cả các cách sử dụng Newx (), Thay mới()và Safefree () được ghi lại bằng người gọi
tệp mã nguồn và số dòng (và tên hàm C, nếu được trình biên dịch C hỗ trợ).
Ngược lại, "-Dm" trực tiếp tại điểm của "malloc ()". Ghi nhật ký SV cũng tương tự.
Vì quá trình ghi nhật ký không sử dụng PerlIO, nên tất cả các phân bổ SV đều được ghi lại và không có thêm SV nào
phân bổ được giới thiệu bằng cách cho phép ghi nhật ký. Nếu được biên dịch với
"-DDEBUG_LEAKING_SCALARS", số sê-ri cho mỗi phân bổ SV cũng được ghi lại.
DDD kết thúc gdb
Những perl gỡ lỗi với giao diện người dùng DDD trên gdb có thể thấy hữu ích sau:
Bạn có thể mở rộng menu phím tắt chuyển đổi dữ liệu, vì vậy, ví dụ: bạn có thể hiển thị một SV
Giá trị IV với một cú nhấp chuột, mà không cần thực hiện bất kỳ thao tác nhập nào. Để làm điều đó, chỉ cần chỉnh sửa ~ / .ddd / init
tập tin và thêm sau:
! Hiển thị các phím tắt.
Ddd * gdbDisplayShortcuts: \
/ t () // Chuyển thành Bin \ n \
/ d () // Chuyển đổi thành Dec \ n \
/ x () // Chuyển đổi thành Hex \ n \
/ o () // Chuyển đổi sang tháng XNUMX (\ n \
hai dòng sau:
((XPV *) (()) -> sv_any) -> xpv_pv // 2pvx \ n \
((XPVIV *) (()) -> sv_any) -> xiv_iv // 2ivx
vì vậy bây giờ bạn có thể thực hiện tra cứu ivx và pvx hoặc bạn có thể cắm vào đó "chuyển đổi" sv_peek:
Perl_sv_peek (my_perl, (SV *) ()) // sv_peek
(My_perl dành cho các bản dựng theo chuỗi.) Chỉ cần nhớ rằng mọi dòng, trừ dòng cuối cùng,
nên kết thúc bằng \ n \
Ngoài ra, chỉnh sửa tệp init một cách tương tác thông qua: nút chuột thứ 3 -> Màn hình mới ->
Chỉnh sửa Menu
Lưu ý: bạn có thể xác định tối đa 20 phím tắt chuyển đổi trong phần gdb.
C đường lùi
Trên một số nền tảng, Perl hỗ trợ truy xuất backtrace cấp C (tương tự như những gì tượng trưng
trình gỡ lỗi như gdb do).
Backtrace trả về dấu vết ngăn xếp của các khung cuộc gọi C, với các tên ký hiệu
(tên hàm), tên đối tượng (như "perl") và nếu có thể, cả mã nguồn
vị trí (tệp: dòng).
Các nền tảng được hỗ trợ là Linux và OS X (một số * BSD có thể hoạt động ít nhất một phần, nhưng
chúng vẫn chưa được thử nghiệm).
Tính năng này chưa được thử nghiệm với nhiều chủ đề, nhưng nó sẽ chỉ hiển thị dấu vết
của chủ đề đang thực hiện backtracing.
Tính năng này cần được bật bằng "Configure -Dusecbacktrace".
"-Dusecbacktrace" cũng cho phép lưu thông tin gỡ lỗi khi biên dịch / liên kết
(thường: "-g"). Nhiều trình biên dịch / trình liên kết hỗ trợ cả việc tối ưu hóa và giữ
thông tin gỡ lỗi. Thông tin gỡ lỗi là cần thiết cho tên ký hiệu và nguồn
Địa điểm.
Các chức năng tĩnh có thể không hiển thị đối với backtrace.
Vị trí mã nguồn, ngay cả khi có sẵn, thường có thể bị thiếu hoặc gây hiểu lầm nếu
trình biên dịch có mã nội tuyến ví dụ. Trình tối ưu hóa có thể thực hiện đối sánh mã nguồn và
mã đối tượng khá khó khăn.
Linux
Bạn phải đã cài đặt thư viện BFD (-lbfd), nếu không "perl" sẽ không liên kết được.
BFD thường được phân phối như một phần của binutils GNU.
Tóm tắt: "Định cấu hình ... -Dusecbacktrace" và bạn cần "-lbfd".
OS X
Các vị trí mã nguồn được hỗ trợ có thể nếu bạn có Công cụ dành cho nhà phát triển
Cài đặt. (BFD là không cần thiết.)
Tóm tắt: "Định cấu hình ... -Dusecbacktrace" và cài đặt Công cụ dành cho nhà phát triển sẽ
tốt.
Theo tùy chọn, để dùng thử tính năng này, bạn có thể muốn bật tính năng kết xuất tự động của
backtrace ngay trước khi phát ra một cảnh báo hoặc thông báo có tiếng kêu cạch cạch (chết), bằng cách thêm
"-Accflags = -DUSE_C_BACKTRACE_ON_ERROR" để Định cấu hình.
Trừ khi tính năng bổ sung ở trên được bật, không có gì về chức năng backtrace
hiển thị, ngoại trừ mức Perl / XS.
Hơn nữa, ngay cả khi bạn đã bật tính năng này để được biên dịch, bạn cần bật nó
trong thời gian chạy với một biến môi trường: "PERL_C_BACKTRACE_ON_ERROR = 10". Nó phải là một
số nguyên cao hơn XNUMX, cho biết số khung hình mong muốn.
Truy xuất backtrace từ mức Perl (ví dụ: sử dụng phần mở rộng XS) sẽ rất nhiều
ít thú vị hơn người ta hy vọng: thông thường bạn sẽ thấy "runops", "enterub", và không
nhiều thứ khác. API này nhằm mục đích được gọi là từ ở trong triển khai Perl, không phải
từ thực thi cấp Perl.
API C cho backtrace như sau:
get_c_backtrace
free_c_backtrace
get_c_backtrace_dump
dump_c_backtrace
Poison
Nếu bạn thấy trong trình gỡ lỗi một vùng bộ nhớ đầy 0xABABABAB hoặc 0xEFEFEFEF hoặc XNUMXxEFEFEFEF đầy bí ẩn, bạn
có thể thấy tác dụng của Poison () macro, xem perlclib.
Chỉ đọc quang phổ
Dưới ithreads, optree chỉ được đọc. Nếu bạn muốn thực thi điều này, hãy kiểm tra xem có ghi
truy cập từ mã lỗi, biên dịch với "-Accflags = -DPERL_DEBUG_READONLY_OPS" để bật
mã phân bổ bộ nhớ op qua "mmap" và đặt nó ở chế độ chỉ đọc khi nó được gắn vào
chương trình con. Bất kỳ quyền ghi nào vào một op đều dẫn đến "SIGBUS" và hủy bỏ.
Mã này chỉ nhằm mục đích phát triển và có thể không di động ngay cả với tất cả Unix
các biến thể. Ngoài ra, nó là một giải pháp 80%, trong đó nó không thể làm cho tất cả các hoạt động chỉ đọc.
Cụ thể, nó không áp dụng cho các phiến op thuộc khối "BEGIN".
Tuy nhiên, là một giải pháp 80%, nó vẫn có hiệu quả, vì nó đã từng bị lỗi trong quá khứ.
Thời Gian is a bool không a bool?
Trên các trình biên dịch trước C99, "bool" được định nghĩa tương đương với "char". Do đó, sự phân công
của bất kỳ loại lớn hơn nào thành "bool" là không an toàn và có thể bị cắt bớt. Macro "cBOOL" tồn tại
để truyền nó một cách chính xác.
Trên những nền tảng và trình biên dịch mà "bool" thực sự là boolean (C ++, C99), điều đó thật dễ dàng
để quên dàn diễn viên. Bạn có thể buộc "bool" thành "char" bằng cách biên dịch với
"-Accflags = -DPERL_BOOL_AS_CHAR". Bạn cũng có thể muốn chạy "Định cấu hình" với một cái gì đó như
-Accflags = '- Wconversion -Không-dấu-chuyển-đổi -Không-rút-ngắn-64-thành-32'
hoặc trình biên dịch tương đương của bạn để giúp dễ dàng phát hiện bất kỳ đoạn cắt không an toàn nào hiển thị
lên.
Sản phẩm .i Mục tiêu
Bạn có thể mở rộng các macro trong foo.c nộp hồ sơ bằng cách nói
tạo foo.i
sẽ mở rộng macro bằng cách sử dụng cpp. Đừng sợ hãi bởi kết quả.
Sử dụng perlhacktips trực tuyến bằng các dịch vụ onworks.net