แบบแผนการตั้งชื่อที่ใช้สำหรับตัวแปรและฟังก์ชั่นใน C [ปิด]


13

ในขณะที่การเข้ารหัสโครงการขนาดใหญ่ใน CI เกิดปัญหาขึ้น ถ้าฉันเขียนรหัสเพิ่มขึ้นเรื่อย ๆ มันจะมีเวลาที่ฉันจะจัดระเบียบรหัสได้ยาก ฉันหมายถึงว่าการตั้งชื่อสำหรับฟังก์ชั่นและตัวแปรสำหรับส่วนต่าง ๆ ของโปรแกรมอาจดูสับสน

ดังนั้นฉันจึงคิดว่ามีแบบแผนการตั้งชื่อที่มีประโยชน์ที่ฉันสามารถใช้กับตัวแปร C และฟังก์ชั่นได้หรือไม่?

ภาษาส่วนใหญ่แนะนำให้ใช้หลักการตั้งชื่อ แต่สำหรับ C สิ่งเดียวที่ฉันได้อ่านจนถึงตอนนี้คือชื่อควรเป็นคำอธิบายสำหรับการอ่านโค้ด

แก้ไข:

ตัวอย่างของตัวอย่างของแบบแผนการตั้งชื่อที่แนะนำ:

ฉันอ่านอนุสัญญาการตั้งชื่อเพิ่มเติมสำหรับ Java บางแห่ง แต่จำไม่ได้ว่าอยู่ที่ไหน


ยกตัวอย่างภาษาที่มีข้อตกลงการตั้งชื่อที่แนะนำ และสถานที่ที่เราสามารถพบอนุสัญญาการตั้งชื่อเหล่านั้นได้
Philip

@Philip เพิ่มตัวอย่าง
Aseem Bansal

1
ไม่ควรมีปัญหากับตัวแปรเนื่องจากคุณไม่ได้ใช้รูปทรงกลม และสำหรับชื่อฟังก์ชัน: ถ้าชื่อของโมดูลคือorder.cคุณสามารถตั้งชื่อฟังก์ชั่นorder_add(), order_del()และเช่น อาจมีระบบเก่าที่บอกคุณว่าชื่อจะต้องไม่ซ้ำกันภายใน 8 อักขระแรก เมื่อคุณสลับไปที่ C ++ ต่อมาโดยบังเอิญคุณจะรักที่จะเขียนorder::add()และorder::del()แล้ว
ott--

คำตอบ:


17

ถ้าฉันเขียนรหัสเพิ่มขึ้นเรื่อย ๆ มันจะมีเวลาที่ฉันจะจัดระเบียบรหัสได้ยาก

นี่คือปัญหาของคุณ: ทำให้องค์กรถูกต้องและสไตล์ควรไหลได้ง่ายขึ้น

อย่ารอที่จะจัดระเบียบรหัสของคุณ: จัดระเบียบรหัสของคุณตามที่คุณไป แม้ว่าภาษานั้นจะไม่เหมาะกับคุณ แต่รหัสก็ควรจะจัดเป็นโมดูลที่มีคัปปลิ้งต่ำและการรวมตัวที่สูง

โมดูลเหล่านี้จะให้เนมสเปซตามธรรมชาติ อักษรย่อของชื่อโมดูล (ถ้ายาว) และชื่อฟังก์ชันนำหน้าพร้อมกับโมดูลเพื่อหลีกเลี่ยงการชน

ในระดับของตัวระบุแต่ละตัวสิ่งเหล่านี้อยู่ในลำดับที่เพิ่มขึ้นของความเป็นส่วนตัว:

  1. เลือกการประชุมและติดกับมัน
    • เช่นfunction_like_this(struct TypeLikeThis variable)เป็นเรื่องปกติ
  2. หลีกเลี่ยงสัญกรณ์ฮังการีอย่างแน่นอน (ขออภัย JNL)

    • นอกเสียจากว่าคุณจะยินดีที่จะใช้มันตามที่ตั้งใจไว้เดิมซึ่งหมายถึงสัญกรณ์ของแอพของ Simonyi แทนที่จะเป็นเวอร์ชั่นที่แย่มาก

      ทำไม? ฉันสามารถเขียนเรียงความเกี่ยวกับเรื่องนี้ แต่ฉันขอแนะนำให้คุณอ่านบทความนี้โดย Joel Spolsky แล้วตามล่าอีกรอบหากคุณสนใจ มีลิงค์ไปยังเอกสารต้นฉบับของ Simonyi ที่ด้านล่าง

  3. หลีกเลี่ยงการพิมพ์ตัวชี้เว้นแต่ว่าพวกเขาเป็นประเภทคุกกี้ทึบแสงอย่างแท้จริง - พวกเขาสับสนเท่านั้น

    struct Type *ok;
    typedef struct Type *TypePtr;
    TypePtr yuck;
    

    ฉันหมายถึงอะไรโดยคุกกี้ชนิดทึบแสง ? บางสิ่งบางอย่างที่ฉันหมายถึงใช้ภายในโมดูล (หรือห้องสมุดหรืออะไรก็ตาม) ซึ่งจะต้องมีการผ่านออกมาในรหัสลูกค้า แต่รหัสลูกค้าที่ไม่สามารถใช้งานได้โดยตรง มันเพิ่งผ่านมันกลับไปที่ห้องสมุด

    ตัวอย่างเช่นไลบรารีฐานข้อมูลอาจเปิดเผยอินเตอร์เฟสเช่น

    /* Lots of buffering, IPC and metadata magic held in here.
       No, you don't get to look inside. */
    struct DBContextT;
    /* In fact, you only ever get a pointer, so let's give it a nice name */
    typedef struct DBContexT *DBContext;
    
    DBContext db_allocate_context(/*maybe some optional flags?*/);
    void db_release_context(DBContext);
    int db_connect(DBContext, const char *connect);
    int db_disconnect(DBContext);
    int db_execute(DBContext, const char *sql);
    

    ตอนนี้บริบทจะทึบกับรหัสลูกค้าเนื่องจากคุณไม่สามารถมองเข้าไปข้างใน คุณเพิ่งส่งมันกลับไปที่ห้องสมุด บางสิ่งที่คล้ายกันFILEนั้นยังทึบแสงและตัวอธิบายไฟล์จำนวนเต็มก็เป็นคุกกี้เช่นกัน แต่ก็ไม่ทึบ


หมายเหตุเกี่ยวกับการออกแบบ

ฉันใช้วลีการมีเพศสัมพันธ์ต่ำและการติดต่อกันสูงด้านบนโดยไม่มีคำอธิบายและฉันรู้สึกไม่ดีเกี่ยวกับเรื่องนั้น คุณสามารถค้นหาและอาจพบผลลัพธ์ที่ดี แต่ฉันจะพยายามพูดสั้น ๆ (อีกครั้งฉันสามารถเขียนเรียงความ แต่จะพยายามไม่ทำ)

ไลบรารีฐานข้อมูลที่ร่างไว้ด้านบนแสดงการมีเพศสัมพันธ์ต่ำเพราะมันเปิดเผยอินเตอร์เฟสขนาดเล็กสู่โลกภายนอก โดยการซ่อนรายละเอียดการใช้งาน (ส่วนหนึ่งด้วยเคล็ดลับคุกกี้ทึบแสง) จะช่วยป้องกันรหัสลูกค้าขึ้นอยู่กับรายละเอียดเหล่านั้น

ลองนึกภาพแทนคุกกี้ทึบแสงเราประกาศโครงสร้างบริบทเพื่อให้มองเห็นเนื้อหาและมีตัวบ่งชี้ไฟล์ซ็อกเก็ตสำหรับการเชื่อมต่อ TCP ไปยังฐานข้อมูล หากในภายหลังเราเปลี่ยนการใช้งานเพื่อรองรับการใช้เซ็กเมนต์หน่วยความจำที่แชร์เมื่อ DB กำลังทำงานบนเครื่องเดียวกันไคลเอนต์จะต้องรวบรวมใหม่แทนที่จะเชื่อมโยงใหม่ ยิ่งไปกว่านั้นไคลเอนต์อาจเริ่มใช้ตัวอธิบายไฟล์เช่นการเรียกsetsockoptเพื่อเปลี่ยนขนาดบัฟเฟอร์เริ่มต้นและตอนนี้ก็จำเป็นต้องเปลี่ยนรหัสเช่นกัน รายละเอียดทั้งหมดเหล่านี้ควรถูกซ่อนอยู่ในโมดูลของเราซึ่งใช้งานได้จริงและทำให้การเชื่อมต่อระหว่างโมดูลมีน้อย

ตัวอย่างยังแสดงให้เห็นถึงการทำงานร่วมกันสูงในที่วิธีการทั้งหมดในโมดูลที่เกี่ยวข้องกับงานเดียวกัน (การเข้าถึงฐานข้อมูล) ซึ่งหมายความว่าเฉพาะรหัสที่จำเป็นต้องรู้เกี่ยวกับรายละเอียดการใช้งาน (นั่นคือเนื้อหาของคุกกี้ของเรา) มีสิทธิ์เข้าถึงได้จริงซึ่งจะช่วยให้การดีบักง่ายขึ้น

คุณจะเห็นว่าการมีข้อกังวลใจเดียวทำให้ง่ายต่อการเลือกคำนำหน้าเพื่อจัดกลุ่มฟังก์ชั่นเหล่านี้เข้าด้วยกัน

ตอนนี้การพูดตัวอย่างนี้เป็นเรื่องง่าย (โดยเฉพาะอย่างยิ่งเนื่องจากมันยังไม่สมบูรณ์) แต่ก็ไม่ได้ช่วยคุณทันที เคล็ดลับคือการดูในขณะที่คุณเขียนและขยายรหัสของคุณสำหรับฟังก์ชั่นที่ทำสิ่งที่คล้ายกันหรือทำงานในประเภทเดียวกัน (ซึ่งอาจจะเป็นผู้สมัครสำหรับโมดูลของตัวเอง) และสำหรับฟังก์ชั่นที่ทำสิ่งต่าง ๆ มากมาย ไม่เกี่ยวข้องกันมากและอาจเป็นผู้สมัครเพื่อแยกออก


คุณช่วยฉันเข้าใจไหมว่าทำไมชาวฮังการีจึงหลีกเลี่ยง อยากรู้เพิ่มเติมเกี่ยวกับมัน :)
JNL

@JNL: ความคิดเห็นสั้นเกินไปที่จะอธิบายอย่างถูกต้อง ฉันขอแนะนำให้คุณโพสต์เป็นคำถามใหม่
Bart van Ingen Schenau

with low coupling and high cohesion. นั่นหมายความว่าอย่างไร? และโปรดอธิบายเกี่ยวกับประเภทคุกกี้ขุ่น ฉันไม่รู้ว่ามันหมายถึงอะไร
Aseem Bansal

ฉันพยายามพูดถึงทั้งสั้นและล้มเหลวอย่างตรงไปตรงมา หวังว่ามันจะช่วยให้คุณเริ่มต้นได้
ไร้ประโยชน์

ฉันตอบกลับหลังจากไม่กี่วัน ขอโทษสำหรับสิ่งนั้น. ฉันอ่านคำอธิบายของlow coupling and high cohesionคุณ ดังนั้นโดยทั่วไปจะหมายถึงแค็ปซูลสิ่งต่าง ๆ เมื่อฉันสามารถและควรจะทำในลักษณะที่ฟังก์ชั่นที่ต้องการจริงควรมีการเข้าถึง มีบางอย่างเข้ามาในหัวฉัน แต่ฉันก็ยังคิดว่าฉันเข้าใจ
Aseem Bansal

5

ในความเห็นของฉัน 90% ของปัญหาการตั้งชื่อจะถูกแก้ไขถ้าคุณคำนึงถึงสามสิ่ง: a)ทำให้ตัวแปรและชื่อฟังก์ชันของคุณเป็นคำอธิบายที่เป็นไปได้ b)มีความสอดคล้องตลอดทั้งรหัสของคุณ (เช่นถ้าฟังก์ชันมีชื่อว่า addNumber a ฟังก์ชั่นที่สองควรตั้งชื่อ multiplyNumber และไม่ใช่ numbersMul) และc)พยายามทำให้ชื่อสั้นถ้าเป็นไปได้เนื่องจากเราจำเป็นต้องพิมพ์

ที่ถูกกล่าวว่าหากคุณต้องการที่จะดูด้านอื่น ๆ ในหัวข้อนี้หน้า Wikipedia ในการตั้งชื่อการประชุมมีรายการสิ่งที่ดีที่คุณควรทราบ นอกจากนี้ยังมี secion บน C และ C ++:

ใน C และ C ++ คำหลักและตัวระบุไลบรารีมาตรฐานส่วนใหญ่จะเป็นตัวพิมพ์เล็ก ในไลบรารีมาตรฐาน C ชื่อย่อนั้นเป็นชื่อที่พบบ่อยที่สุด (เช่น isalnum สำหรับการทดสอบฟังก์ชั่นว่าตัวอักษรเป็นตัวอักษรและตัวเลข) ในขณะที่ไลบรารีมาตรฐาน C ++ มักใช้เครื่องหมายขีดล่างเป็นตัวคั่นคำ (เช่น out_of_range) ตัวระบุที่เป็นตัวแทนของมาโครคือโดยการประชุมเขียนโดยใช้ตัวอักษรตัวพิมพ์ใหญ่และเครื่องหมายขีดล่างเท่านั้น (ซึ่งเกี่ยวข้องกับการประชุมในภาษาการเขียนโปรแกรมจำนวนมากที่ใช้ตัวระบุตัวพิมพ์ใหญ่สำหรับค่าคงที่) ชื่อที่มีการขีดเส้นใต้คู่หรือเริ่มต้นด้วยการขีดเส้นใต้และอักษรตัวใหญ่ถูกสงวนไว้สำหรับการดำเนินการ (คอมไพเลอร์, ห้องสมุดมาตรฐาน) และไม่ควรใช้ (เช่นสงวน _ หรือ _Reserved) [5] [6] นี่คือเผิน ๆ คล้ายกับการลูบ แต่ความหมายแตกต่างกัน:


3
"พยายามทำให้ชื่อสั้นลงถ้าเป็นไปได้" ใช้ IDE ด้วยการทำให้สมบูรณ์อัตโนมัติชื่อฟังก์ชันของคุณอาจยาวและเป็นคำอธิบายตามที่พวกเขาต้องการให้เป็นตามที่คุณต้องการพิมพ์เพียงครั้งเดียว
Joel

1
@Joel คำแนะนำที่น่ากลัว ไม่ใช่ทุกคนที่จะใช้ IDE เดียวกันกับคุณ
James

6
@ James พวกเขาไม่ต้องการพวกเขาสามารถใช้ IDE ที่เหมาะสมได้ จากนั้นคุณไม่ต้องเสียสละความชัดเจนในการผลิต
Joel

คำว่า IDE ถูกยืดออกไปเล็กน้อยในแต่ละวัน เทคนิค Notepad ++ เป็น IDE เพราะคุณสามารถกำหนดค่าให้คอมไพล์และเรียกใช้โครงการของคุณได้ แต่ส่วนใหญ่จะเป็นตัวแก้ไขข้อความ และทำให้สมบูรณ์โดยอัตโนมัติ
ฟิลิป

5

ข้อ จำกัด อย่างเดียวใน C คือไม่มีเนมสเปซ ดังนั้นคุณต้องหาวิธีที่จะทำให้rename()ฟังก์ชั่นของไลบรารีระบบไฟล์ของคุณแตกต่างจากrename()ฟังก์ชั่นของไลบรารีสื่อของคุณ วิธีการแก้ปัญหาตามปกติคือคำนำหน้าเช่น: และfilesystem_rename()media_rename()

คำแนะนำทั่วไปอื่น ๆ คือ: คงเส้นคงวาภายในโครงการหรือทีม การอ่านจะได้รับการปรับปรุง


+1: นั่นเป็นจริงอย่างยิ่งสำหรับสัญลักษณ์ที่ส่งออกในไลบรารี "ฉันขอโทษ แต่ห้องสมุดระบบแฟ้มที่ไม่ได้ไปกับห้องสมุดสื่อว่าเพราะทั้งสองมีการเปลี่ยนชื่อฟังก์ชั่นการส่งออก.
เหลือ

2

หากคุณกำลังมองหารูปแบบที่ยอมรับทั่วโลก

MISRA / JSF / AUTOSAR ครอบคลุมเกือบ 100% ของทุก ๆ มาตรฐานอุตสาหกรรมสำหรับการตั้งชื่อและจัดระเบียบรหัส C / C ++ ปัญหาคือพวกเขาจะไม่เสียค่าใช้จ่ายในการถือครองนั่นคือหนังสือคู่มือแต่ละเล่มมีค่าใช้จ่าย ฉันรู้ว่า MISRA 2008 C / C ++ การเข้ารหัสหนังสือมาตรฐานอาจมีค่าใช้จ่ายประมาณ 50 USD

คุณสามารถคิดว่าสิ่งเหล่านี้เป็นหนังสืออ้างอิงฮาร์วาร์ดสำหรับบรรณานุกรมและการอ่านเพิ่มเติมเมื่อคุณเขียนบันทึกประจำวัน ฉันใช้ MISRA และเป็นวิธีที่ดีในการตั้งชื่อฟังก์ชั่นและตัวแปรของคุณและจัดระเบียบเพื่อการใช้งานที่เหมาะสม

หากคุณกำลังมองหาบางสิ่งบางอย่างชั่วคราว

การอ้างอิงที่คุณให้ไว้สำหรับ Python และ Java นั้นโอเคฉันเดาได้ ฉันเคยเห็นคนที่รับความคิดเห็นในรูปแบบ javadoc การตั้งชื่อและการจัดระเบียบโค้ด ตามความเป็นจริงในโครงการสุดท้ายของฉันฉันต้องเขียนโค้ด C ++ ในฟังก์ชั่น / ชื่อตัวแปรแบบชวา เหตุผลสองประการที่อยู่เบื้องหลังนี้:

1) ดูเหมือนง่ายกว่าที่จะติดตาม

2) ข้อกำหนดของรหัสการผลิตไม่ได้สัมผัสกับมาตรฐานระบบความปลอดภัยที่สำคัญ

3) รหัสดั้งเดิมคือ (อย่างใด) ในรูปแบบนั้น

4) Doxygen อนุญาตให้ Javadoc sytle commenting ในขณะนั้นเรากำลังใช้ doxygen เพื่อสร้างเอกสารสำหรับผู้ผลิต

โปรแกรมเมอร์หลายคนจะเป็นคู่ต่อสู้ของเรื่องนี้ แต่โดยส่วนตัวแล้วฉันไม่มีอะไรผิดปกติกับการตั้งชื่อฟังก์ชั่น / การตั้งชื่อตัวแปรแบบ javadoc ใน C / C ++ ใช่ของหลักสูตรการปฏิบัติในการจัดระเบียบการควบคุมการไหลของคุณความปลอดภัยของด้าย ฯลฯ จะต้องได้รับการจัดการโดยไม่คำนึงถึง อย่างไรก็ตามฉันไม่ใช่ผู้สมัครที่นี่ ฉันยังไม่รู้ด้วยว่าข้อกำหนดรูปแบบรหัสการผลิตของคุณเข้มงวดแค่ไหน ฉันขอแนะนำให้คุณตรวจสอบข้อกำหนดของคุณค้นหาว่าคุณขึ้นอยู่กับการประชุมการตั้งชื่อที่เฉพาะเจาะจงอย่างไรและไปกับโซลูชันที่กล่าวถึงในคำตอบของฉันและของผู้อื่น

หวังว่านี่จะช่วยได้!


ที่จริงฉันขอรหัส C ส่วนตัวนี้ แต่ฉันจะจำข้อเสนอแนะของคุณ
Aseem Bansal

@ AseemBansal ส่วนตัวหรืออาชีพเหล่านั้นดีที่จะเรียนรู้และยังดีที่จะใส่ประวัติย่อของคุณ :) .... ขึ้นอยู่กับคุณ
hagubear

0

สิ่งสำคัญที่ควรพิจารณาในขณะตั้งชื่อคือ

  1. ดูประเภท actionObject หรือ ObjectAction (Object Not for C แต่โดยทั่วไปเมื่อคุณไปที่ Object Oriented Languages ​​อื่น ๆ ) สิ่งนี้จะช่วยได้

  2. ส่วนที่เหลือจะเป็นอย่างต่อเนื่องสั้นและเป็นคำอธิบายได้อย่างแน่นอน

  3. นอกจากนี้ยังมีวัตถุประสงค์เพียงอย่างเดียวของทุกตัวแปรและฟังก์ชั่นที่กำหนดไว้เช่น: ถ้ามันจะเก็บค่าชั่วคราวชื่อมันเป็น nTempVal สำหรับ int
  4. ตัวแปรควรเป็นคำนามและเมธอดควรเป็นคำกริยา

6
สัญกรณ์ฮังการี (คำนำหน้าตัวแปรด้วยตัวอักษรแสดงประเภท) นำไปสู่การไม่มีสิ้นสุดของความเจ็บปวด มันได้หายไปจากแฟชั่นส่วนใหญ่ขอบคุณ
Gort the Robot

@StevenBurnap เป็นเพียงอยากรู้ว่าทำไมรูปแบบฮังการีจึงหลีกเลี่ยง? ฉันเชื่อว่านั่นคือสิ่งที่พวกเขาสอนเราในโรงเรียนและฉันก็เห็นรหัสดังกล่าวในที่ทำงานบางแห่งด้วย คุณจะแนะนำแบบไหนถ้าไม่ใช่ชาวฮังการี ขอบคุณ
JNL

1
รูปแบบการตั้งชื่อที่ดีที่สุดเป็นเพียงการใช้อย่างต่อเนื่องโดยมีชื่อที่ชัดเจนและเป็นคำอธิบายที่ค่อนข้างสั้นโดยไม่มีตัวย่อมากเกินไปและหลีกเลี่ยงคำนำหน้าซ้ำซ้อน สัญกรณ์ฮังการีมียูทิลิตี้จริงเล็กน้อยทำให้การอ่านรหัสยากขึ้นและทำให้การเปลี่ยนประเภทยากขึ้น
Gort the Robot

2
นี่คือคำอธิบายของความตั้งใจดั้งเดิมและสิ่งที่น่ารังเกียจที่เอกสารของฮังการีได้กลายเป็น: joelonsoftware.com/articles/Wrong.html
Residuum

@ Residuum นั่นเป็นการเชื่อมโยงที่ดี ช่วยได้มาก ขอบคุณมัน
JNL

0

คำตอบส่วนใหญ่ดี แต่ฉันต้องการพูดบางอย่างเกี่ยวกับการตั้งชื่อแบบแผนสำหรับ libaries และไฟล์ที่รวมอยู่คล้ายกับการใช้เนมสเปซในภาษาอื่นเช่น C ++ หรือ Java:

หากคุณสร้างห้องสมุดค้นหาคำนำหน้าทั่วไปสำหรับสัญลักษณ์ที่ส่งออกของคุณเช่นฟังก์ชั่นทั่วโลก, พิมพ์และตัวแปร สิ่งนี้จะช่วยป้องกันไม่ให้เกิดการขัดแย้งกับห้องสมุดอื่น ๆ และระบุฟังก์ชั่นที่มาจากของคุณ นี่เป็นแอพเล็ก ๆ น้อย ๆ ของสัญกรณ์ฮังการี

อาจดำเนินการต่อไปและจัดกลุ่มสัญลักษณ์ที่ส่งออกของคุณ: libcurl ใช้ curl_ * สำหรับสัญลักษณ์ทั่วโลก, curl_easy_ *, curl_multi_ * และ curl_share_ * สำหรับอินเทอร์เฟซที่แตกต่างกัน ดังนั้นนอกเหนือจากการใช้ curl_ * สำหรับฟังก์ชั่นทั้งหมดพวกเขาได้เพิ่ม "namespaces" อีกระดับสำหรับอินเทอร์เฟซต่าง ๆ : การเรียกใช้ฟังก์ชัน curl_easy_ * บนตัวจัดการ curl_multi_ * ตอนนี้ดูผิดให้ดูชื่อฟังก์ชันที่http: // curl haxx.se/libcurl/c/

การรักษากฎสำหรับสัญลักษณ์ที่ส่งออกคุณควรใช้กฎเหล่านั้นสำหรับฟังก์ชั่นสแตติกใน#includeไฟล์ ed: ลองค้นหาคำนำหน้าทั่วไปสำหรับฟังก์ชั่นเหล่านี้ บางทีคุณอาจมีฟังก์ชั่นยูทิลิตี้สตริงคงที่ในไฟล์ชื่อ "my_string"? คำนำหน้าฟังก์ชั่นทั้งหมดที่มี my_string_ *


โดยสัญลักษณ์ที่ส่งออกหมายถึงตัวแปรทั่วโลกฟังก์ชั่นประเภทอื่น ๆ หากฉันถูกต้อง คุณช่วยอธิบายเกี่ยวกับการจัดกลุ่มสัญลักษณ์ที่ส่งออกได้ไหม ฉันคิดว่าคุณอธิบายว่าในย่อหน้าก่อนหน้าแล้ว คุณเพิ่มอะไรลงไปในย่อหน้าที่ 3
Aseem Bansal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.