Pretty C เป็นภาษาสคริปต์ใหม่ที่เข้ากันได้กับ C Pretty C เพิ่มประสิทธิภาพโปรแกรมของคุณด้วยการพิมพ์แบบไดนามิก การวนซ้ำทั่วไป การติดตามทรัพยากร และรายละเอียดอื่นๆ และมันเข้ากันได้กับ C และไลบรารีทั้งหมดของมัน! แรงบันดาลใจจาก Lua, Python, JavaScript และ Lisp ต่อไปนี้คือวิธีที่การนำ head
utility ไปใช้ใหม่อย่างไร้เดียงสาอาจดูเหมือนกับ Pretty C:
#include "pretty.h"
int main ( int argc , string argv [])
{
if ( argc above 1 )
with ( f , fclose , fopen ( argv [ 1 ], "r" ))
fortimes ( line , 10 )
with ( buf , free , vector ( 200 , char , 0 ))
when ( fgets ( buf , 200 , f ))
then print ( buf )
otherwise 0 ;
else
println ( "Please provide an input file" );
return EXIT_SUCCESS ;
}
เป้าหมายของ Pretty C คือ:
#include
-able จากไฟล์ C ใดก็ได้!) เพื่อเปลี่ยนโค้ดเบสใด ๆ ให้กลายเป็นโค้ดที่เป็นมิตรสำหรับผู้เริ่มต้นชำระเงินที่เก็บข้อมูล
git clone https://github.com/aartaka/pretty.c
หรือเพียงแค่คัดลอกไฟล์ pretty.h
เพราะ Pretty C เป็นไลบรารี่แบบส่วนหัวเท่านั้น คุณจึงสามารถทำได้
#include "pretty.h"
จากไฟล์ใด ๆ ในไดเร็กทอรีที่คุณวาง pretty.h
ไปที่ หรือจากไฟล์ใดๆ จริงๆ หากคุณระบุเส้นทางไปยัง Pretty C เป็นเส้นทางรวม ( -I
)
นี่คือการเปลี่ยนแปลงที่สวยงามทั้งหมดที่ทำให้ C hip กลับมาอีกครั้ง
true
, false
และ bool
uint64_t
and
สำหรับ &&
และ or
สำหรับ ||
- ประณีต! ทุกคนเป็นผู้กำหนดสิ่งเหล่านี้ ดังนั้นทำไมไม่จัดเตรียมไว้ล่ะ?
max
และ min
ของตัวเลขสองตัวlen
สำหรับความยาวอาเรย์default
สำหรับการระบุค่าทางเลือกlimit
เพื่อให้แน่ใจว่าช่วงค่าที่เหมาะสมbetween
เพื่อตรวจสอบว่าตัวเลขอยู่ในช่วงหรือไม่divisible
เพื่อตรวจสอบว่าตัวเลขแบบโมดูโลหารด้วยตัวเลขอื่นหรือไม่ ประเภทนามแฝง:
string
== char*
byte
== char
bytes
== char*
any
== void*
uchar
ushort
.uint
ulong
ส่วนใหญ่สร้างแบบจำลองตาม Lua และ Lisp:
eq
เนื่องจาก iso646.h
มีเพียง not_eq
เท่านั้นis
หมายถึง ==
เช่นกันbitnot
และ bitxor
สำหรับการดำเนินการที่เคยถูกเรียกไม่สอดคล้องกัน ( compl
และ xor
ตามลำดับ) ใน iso646.h
success
และ fail
/ failure
สำหรับรูปแบบ success == 0
.below
above
upto
และ downto
even
, odd
, positive
, negative
, zero
และ empty
เป็นเพรดิเคตสำหรับตัวเลข/ข้อมูลnil
สำหรับ NULL
until
ถูกปฏิเสธ while
elif
เป็น else if
ifnt
for if(!...)
และ elifnt
(คุณเดาได้)repeat
จาก Lua เป็นนามแฝงสำหรับ do
done~/~finish
และ pass
เป็นนามแฝงสำหรับ break
และ continue
ตามลำดับalways
, forever
, loop
และ indefinitely
เพื่อให้คุณสามารถสร้างลูปไม่สิ้นสุด (เหตุการณ์? เซิร์ฟเวอร์?) always println ( "After all this time?" );
never
comment
เพื่อแสดงความคิดเห็นในโค้ดด้วยคำหลักเพียงคำเดียว ในขณะที่ยังคงอนุญาตให้คอมไพเลอร์วิเคราะห์/ปรับให้เหมาะสม (คล้ายกับแบบฟอร์ม comment
Clojure): never println ( "This never runs, but never gets outdated, because compiler will shout at you if it does." );
ใช่คุณสามารถทำได้
var t = time ( 0 );
let lt = localtime ( & t );
local at = asctime ( lt );
println ( at );
กับพริตตี้ซี
print
สิ่งที่คุณป้อน println
จะเพิ่มบรรทัดใหม่หลังจากนั้น
println ( 3.1 );
print ( "Hello world!n" );
เปรียบเทียบทุกสิ่ง!
equal ( "NA" , line ); // true
equal ( 0.3 , 0.2 + 0.1 ); // true
ternaries นั้นน่ากลัว ดังนั้นการเพิ่มข้อความธรรมดาลงไปก็ไม่เสียหาย if
มีการดำเนินการ else
แต่มีทางเลือกทางภาษาที่เหมาะสมซึ่งมีลักษณะค่อนข้างคล้าย Python / Lisp:
return when some_condition
then do_something ()
other do_something_else ();
มันเป็นไตรภาคด้านล่าง:
when
ขยายเป็นสตริงว่างและมีไว้เพื่อให้อ่านง่ายเท่านั้นunless
จะขยายให้ not
เป็นเวอร์ชันเชิงลบของ when
then
ขยายเป็น ?
-other
/ otherwise
จะขยายเป็น :
. นอกจากนี้ยังมี only
เมื่อส่วนคำสั่ง otherwise
ไม่จำเป็น:
return when done ()
then 42 only ;
และ otherwhen
สำหรับเงื่อนไขต่อไป
return when c is 'A'
then 'a'
otherwhen c is 'B'
then 'b' only ;
for
มาโคร มาโครเหล่านี้เป็นนามแฝงสำหรับรูปแบบลูป for
รูปแบบ โดยแต่ละรายการจะแยกการใช้ for
loop ที่พบบ่อยบางส่วนออกไป
foreach (var, type, length, ...)
อันนี้เดินอาร์เรย์หรือขอบเขตหน่วยความจำที่เตรียมใช้งานกับนิพจน์ vararg ทุกครั้งที่มันวนซ้ำ var
จะถูกตั้งค่าให้เป็นตัวชี้ไปยังองค์ประกอบอาร์เรย์ที่เกี่ยวข้อง ใช่ ตัวชี้—เพื่อให้คุณสามารถแก้ไของค์ประกอบในตำแหน่งนั้นได้หากต้องการ
foreach ( i , int , 10 , vector ( 10 , int , 1 , 2 , 3 , 3 , 4 , 5 ))
println ( * i );
แสดงการใช้ vector
ด้วย
forthese (var, type, ...)
วนซ้ำ varargs ที่ให้มา โดยผูกแต่ละรายการเหล่านี้กับ type
-d var
วงด้านบนสามารถแปลเป็น:
forthese ( i , int , 1 , 2 , 3 , 3 , 4 , 5 )
println ( i );
fortimes (var, times)
กรณีที่เกิดขึ้นบ่อยครั้งจาก 0 ไปเป็นจำนวนบวกบางจำนวน ช่วยคุณประหยัดเวลาได้มากทีเดียว
for ( int i = 0 ; i < 28 ; i ++ )
println ( i + 1 );
เปลี่ยนมันให้เป็นเรื่องง่าย
fortimes ( i , 28 )
println ( i + 1 );
println ( "28 stab wounds, you didn't want to leave him a chance, huh?" );
forrange (var, init, target)
วนซ้ำช่วงตัวเลขตั้งแต่ init
ถึง target
ไพธอนเนสก์. นี่คือลูปการแปลงเซลเซียสเป็นฟาเรนไฮต์ด้วย forrange
:
forrange ( c , -10 , 20 )
printf ( "Celsius %i = Fahrenheit %fn" , c , ( 32 + ( c * 1.8 )));
โปรดทราบว่า init
และ target
เป็นจำนวนเต็มตามอำเภอใจ ทั้งแบบลงนามและไม่ได้ลงนาม และ init
อาจมากกว่า target
ซึ่งในกรณีนี้ขั้นตอนการวนซ้ำจะลดตัวแปรลง
forrangeby (var, type, init, target, by)
วนซ้ำ type
-d var
จาก iter
ไปยัง target
by
ขั้นทุกครั้ง ไพธอนเนสก์.
forrangeby ( x , double , 1.0 , 10.0 , 0.5 )
println ( x );
สิ่งเหล่านี้ช่วยให้สามารถจัดสรรรูปแบบทั่วไปได้อย่างรวดเร็วและสกปรก ส่วนใหญ่สร้างโมเดลหลังจาก C++
new (type, ...)
โอเปอเรเตอร์ new
C++ นั้นดี ดังนั้นมันจะไม่เจ็บถ้ามีอะไรที่คล้ายกันใน C ใช่ไหม ไม่ต้องถามอีกต่อไป:
struct ListNode {
int val ;
struct ListNode * next ;
};
struct ListNode * node = new ( struct ListNode , 2 , new ( struct ListNode , 1 , nil ));
หรือถ้าคุณชอบ คุณสามารถเพิ่มไวยากรณ์เพิ่มเติมที่ด้านบนได้:
#define cons ( val , ...) new(struct ListNode, val, __VA_ARGS__)
cons ( 2 , cons ( 1 , nil ));
vector (length, type, ...)
ซี++อีกแล้ว std::vector
เป็นโครงสร้างข้อมูลที่มีประโยชน์และหลากหลายซึ่งง่ายต่อการให้เหตุผล แม้ว่ามาโครนี้จะไม่ได้มีคุณสมบัติจากระยะไกลเหมือนกับภาษา C++ แต่ก็ทำให้รูปแบบ “จัดสรรอาร์เรย์ขององค์ประกอบจำนวนมากนั้นและเนื้อหาเหล่านี้” บ่อยครั้งง่ายขึ้น:
double * vec = vector ( 10 , double , 1 , 2 , 3 , 4 , 5 );
delete (...)
ในกรณีที่คุณไม่ชอบการใช้ทรัพยากร free
และต้องการชื่อ C ++ ที่น่าดึงดูดกว่า
อย่างอื่นก็ free
เหมือนกัน
สิ่งเหล่านี้จะสร้างการเชื่อมโยงภายในเครื่องใหม่ ตรวจสอบให้แน่ใจว่าการคำนวณถูกเลื่อนออกไป หรือดำเนินการกับบล็อกที่ตามมา
lambda (ret, name, ...)
(GCC, Clang หรือ C++)ฟังก์ชั่นที่ซ้อนกัน/lambdas/closures ตอนนี้อยู่ใน C!
int * arr = vector ( 10 , int , 23423 , 23423 , 234 , 5233 , 6 , 4 , 34 , 643 , 3 , 9 );
lambda ( int , cmp , int * a , int * b ) {
return * a - * b ;
};
qsort ( arr , 10 , sizeof ( int ), cmp );
// arr becomes {3, 4, 6, 9, 34, 234, 643, 5233, 23423, 23423}
with (var, close, ...)
วิธีนี้ช่วยให้แน่ใจว่าคุณจะไม่มีวันใช้งานฟรีอีกต่อไป เนื่องจากคุณจัดเตรียมขั้นตอนการปลดปล่อย ( close
) ไว้ล่วงหน้า มีประโยชน์อย่างยิ่งสำหรับอ็อบเจ็กต์และตัวกำหนดไฟล์ที่จัดสรรแบบไดนามิก
with ( file , fclose , fopen ( "hello.txt" , "w" ))
fprintf ( file , "Hello world!n" );
ข้อเสียประการหนึ่งคือ var
ที่ถูกผูกไว้นั้นเป็น void *
ดังนั้นคุณอาจต้องบังคับมันให้ตรงกับประเภทของคุณก่อนใช้งาน
defer (...)
ออฟโหลดโค้ดที่จะดำเนินการหลังจากบล็อกต่อไปนี้ ไม่ใช่จุดสิ้นสุดของฟังก์ชันเหมือนใน Go เพราะนั่นคือ เป็นไปไม่ได้ ใช้งานยากใน C ถึงกระนั้น Pretty C defer
ก็มีประโยชน์เพียงพอ
try
catch
การจัดการข้อผิดพลาดแฟนซี ขณะนี้อยู่ในตัวอย่าง C. Refactored จากการอ้างอิง errno:
try log ( 0.0 );
catch ( NOERR )
println ( "No error." );
catch ( EDOM , ERANGE )
println ( "Math error!" );
Pretty C ยังให้บริการ NOERR
และ NOERROR
เพื่อความสะดวกในการสลับเคสข้อผิดพลาด
make indent
ก่อนที่จะคอมมิต ซึ่งควรจัดการรายละเอียดสไตล์ส่วนใหญ่