คุณเปรียบเทียบสองอินสแตนซ์ของ structs เพื่อความเท่าเทียมในมาตรฐาน C ได้อย่างไร
คุณเปรียบเทียบสองอินสแตนซ์ของ structs เพื่อความเท่าเทียมในมาตรฐาน C ได้อย่างไร
คำตอบ:
C ไม่มีสิ่งอำนวยความสะดวกด้านภาษาในการทำสิ่งนี้ - คุณต้องทำด้วยตัวเองและเปรียบเทียบโครงสร้างสมาชิกแต่ละรายโดยสมาชิก
0.0, -0.0 NaN
memcmp()
ตัวชี้ที่แตกต่างกันในการเป็นตัวแทนไบนารีอาจชี้ไปที่ตำแหน่งเดียวกัน (เช่น DOS: seg: offset) และอื่น ๆ ที่เท่ากัน บางระบบมีพอยน์เตอร์พอยน์เตอร์หลายตัวที่เปรียบเทียบกัน เหมือนกันสำหรับคลุมเครือint
กับ -0 และชนิดจุดลอยที่มีการเข้ารหัสซ้ำซ้อน (Intel ยาวสองเท่า, ทศนิยม 64, ฯลฯ ) ปัญหาเหล่านี้ไม่ได้calloc()
ใช้หรือแตก
==
ไม่ทำงานกับโครงสร้าง (เช่นฉัน) โปรดดูstackoverflow.com/questions/46995631/ …
คุณอาจถูกล่อลวงให้ใช้memcmp(&a, &b, sizeof(struct foo))
แต่มันอาจไม่ทำงานในทุกสถานการณ์ คอมไพเลอร์อาจเพิ่มพื้นที่บัฟเฟอร์การจัดตำแหน่งให้กับโครงสร้างและค่าที่พบในตำแหน่งหน่วยความจำที่วางอยู่ในพื้นที่บัฟเฟอร์ไม่รับประกันว่าจะเป็นค่าใด ๆ
แต่ถ้าคุณใช้calloc
หรือmemset
ขนาดเต็มของโครงสร้างก่อนที่จะใช้พวกเขาคุณสามารถทำการเปรียบเทียบแบบตื้นด้วยmemcmp
(ถ้าโครงสร้างของคุณมีตัวชี้มันจะจับคู่เฉพาะถ้าที่อยู่ที่ตัวชี้จะชี้ไปที่เดียวกัน)
memcmp
โดยที่ล้างหน่วยความจำก่อน ซึ่งอยู่ใกล้กับการทำงาน แต่ไม่ถูกต้อง Ofc คำถามยังไม่ได้กำหนด "ความเท่าเทียมกัน" ดังนั้นถ้าคุณใช้มันเพื่อหมายถึง "ความเท่าเทียมกันของการแทนค่าวัตถุที่เป็นไบต์" แล้วmemcmp
ทำสิ่งนั้นอย่างแน่นอน (ไม่ว่าจะล้างหน่วยความจำหรือไม่
ถ้าคุณทำมันมากฉันขอแนะนำให้เขียนฟังก์ชั่นที่เปรียบเทียบทั้งสองโครงสร้าง ด้วยวิธีนี้หากคุณเปลี่ยนโครงสร้างคุณจะต้องเปลี่ยนการเปรียบเทียบในที่เดียว
สำหรับวิธีที่จะทำ .... คุณต้องเปรียบเทียบทุกองค์ประกอบแยกกัน
คุณไม่สามารถใช้ memcmp เพื่อเปรียบเทียบ structs เพื่อความเท่าเทียมกันเนื่องจากอาจมีการขยายตัวของอักขระแบบสุ่มระหว่างฟิลด์ใน struct
// bad
memcmp(&struct1, &struct2, sizeof(struct1));
ข้างต้นจะล้มเหลวสำหรับ struct เช่นนี้
typedef struct Foo {
char a;
/* padding */
double d;
/* padding */
char e;
/* padding */
int f;
} Foo ;
คุณต้องใช้การเปรียบเทียบสมาชิกที่ชาญฉลาดเพื่อความปลอดภัย
@Greg ถูกต้องที่หนึ่งจะต้องเขียนฟังก์ชั่นการเปรียบเทียบที่ชัดเจนในกรณีทั่วไป
มันเป็นไปได้ที่จะใช้memcmp
ถ้า:
NaN
ได้-Wpadded
กับ clang เพื่อตรวจสอบสิ่งนี้) หรือ structs ถูกเตรียมใช้งานอย่างชัดเจนด้วยmemset
เมื่อเริ่มต้นBOOL
) ที่มีค่าแตกต่างกัน แต่เทียบเท่าหากคุณไม่ได้เขียนโปรแกรมสำหรับระบบฝังตัว (หรือเขียนไลบรารีที่อาจใช้กับพวกเขา) ฉันจะไม่กังวลเกี่ยวกับตัวพิมพ์มุมบางตัวในมาตรฐาน C ความแตกต่างของตัวชี้ใกล้กับไกลไม่มีอยู่ในอุปกรณ์ 32- บิตหรือ 64- บิต ไม่มีระบบที่ไม่ฝังที่ฉันรู้จักมีพNULL
อยน์เตอร์หลายตัว
อีกทางเลือกหนึ่งคือการสร้างฟังก์ชั่นความเท่าเทียมกันโดยอัตโนมัติ หากคุณวางคำจำกัดความของโครงสร้างในวิธีที่ง่ายมันเป็นไปได้ที่จะใช้การประมวลผลข้อความอย่างง่ายในการจัดการคำจำกัดความของโครงสร้างที่เรียบง่าย คุณสามารถใช้ libclang สำหรับกรณีทั่วไป - เนื่องจากใช้ส่วนหน้าเดียวกับ Clang จึงจัดการกรณีมุมทั้งหมดได้อย่างถูกต้อง (ยกเว้นข้อบกพร่อง)
ฉันไม่เห็นไลบรารี่การสร้างรหัสดังกล่าว อย่างไรก็ตามมันดูค่อนข้างง่าย
อย่างไรก็ตามเป็นกรณีที่ฟังก์ชันความเสมอภาคที่สร้างขึ้นเช่นนี้มักจะทำสิ่งผิดพลาดในระดับแอปพลิเคชัน ตัวอย่างเช่นควรเปรียบเทียบสองUNICODE_STRING
โครงสร้างใน Windows อย่างตื้นหรือลึก?
หมายเหตุคุณสามารถใช้ memcmp () กับ stuctures ที่ไม่คงที่โดยไม่ต้องกังวลเกี่ยวกับการขยายหากคุณไม่ได้กำหนดค่าเริ่มต้นสมาชิกทั้งหมด (พร้อมกัน) สิ่งนี้ถูกกำหนดโดย C90:
{0, }
จะเป็นศูนย์ไบต์ใด ๆ ?
ขึ้นอยู่กับว่าคำถามที่คุณถามคือ:
ในการตรวจสอบว่ามันเป็นวัตถุเดียวกันหรือไม่ให้เปรียบเทียบพอยน์เตอร์กับ structs สองตัวเพื่อความเท่าเทียมกัน หากคุณต้องการค้นหาโดยทั่วไปหากพวกเขามีค่าเท่ากันคุณจะต้องทำการเปรียบเทียบอย่างลึกซึ้ง สิ่งนี้เกี่ยวข้องกับการเปรียบเทียบสมาชิกทั้งหมด หากสมาชิกเป็นตัวชี้ไปยัง structs อื่น ๆ คุณจะต้องจ่ายเงินคืนใน structs เหล่านั้นด้วย
ในกรณีพิเศษที่ structs ไม่มีพอยน์เตอร์คุณสามารถทำ memcmp เพื่อทำการเปรียบเทียบข้อมูลที่มีอยู่ในแต่ละบิตโดยไม่ต้องรู้ว่าข้อมูลหมายถึงอะไร
ตรวจสอบให้แน่ใจว่าคุณรู้ว่า 'เท่ากับ' หมายความว่าอย่างไรสำหรับสมาชิกแต่ละคน - มันชัดเจนสำหรับ ints แต่จะละเอียดกว่าเมื่อพูดถึงค่าทศนิยมหรือประเภทที่ผู้ใช้กำหนด
memcmp
ไม่ได้เปรียบเทียบโครงสร้าง memcmp
เปรียบเทียบไบนารีและมีขยะในโครงสร้างเสมอดังนั้นมันจะออกมาเป็นเท็จในการเปรียบเทียบเสมอ
เปรียบเทียบองค์ประกอบตามองค์ประกอบที่ปลอดภัยและจะไม่ล้มเหลว
หาก structs มีเพียงข้อมูลพื้นฐานเท่านั้นหรือหากคุณสนใจในความเท่าเทียมที่เข้มงวดคุณสามารถทำสิ่งนี้ได้:
int my_struct_cmp (const struct my_struct * lhs, const struct my_struct * rhs) { ส่งคืน memcmp (lhs, rsh, sizeof (struct my_struct)); }
อย่างไรก็ตามหากโครงสร้างของคุณมีตัวชี้ไปยังโครงสร้างหรือสหภาพอื่น ๆ คุณจะต้องเขียนฟังก์ชันที่เปรียบเทียบแบบดั้งเดิมอย่างเหมาะสมและทำการเปรียบเทียบการเรียกเปรียบเทียบกับโครงสร้างอื่นตามความเหมาะสม
อย่างไรก็ตามโปรดทราบว่าคุณควรใช้ memset (& a, sizeof (struct my_struct), 1) เพื่อไม่ให้ช่วงของหน่วยความจำของโครงสร้างเป็นศูนย์ซึ่งเป็นส่วนหนึ่งของการเริ่มต้น ADT ของคุณ
ถ้าตัวแปร 2 โครงสร้างถูกกำหนดค่าเริ่มต้นด้วย calloc หรือถูกตั้งค่าเป็น 0 โดย memset เพื่อให้คุณสามารถเปรียบเทียบ 2 โครงสร้างของคุณกับ memcmp และไม่ต้องกังวลกับขยะโครงสร้างและสิ่งนี้จะช่วยให้คุณได้รับเวลา
ตัวอย่างที่สอดคล้องกับนี้ใช้ส่วนขยายคอมไพเลอร์แพ็ค #pragma จาก Microsoft Visual Studio เพื่อให้แน่ใจว่าสมาชิกโครงสร้างจะถูกบีบอัดให้แน่นที่สุด:
#include <string.h>
#pragma pack(push, 1)
struct s {
char c;
int i;
char buffer[13];
};
#pragma pack(pop)
void compare(const struct s *left, const struct s *right) {
if (0 == memcmp(left, right, sizeof(struct s))) {
/* ... */
}
}