อยู่ที่ไหนMIN
และMAX
กำหนดไว้ใน C ถ้าทั้งหมด?
เป็นวิธีที่ดีที่สุดในการใช้สิ่งเหล่านี้โดยทั่วไปและพิมพ์อย่างปลอดภัยที่สุดเท่าที่จะทำได้? (ส่วนขยายคอมไพเลอร์ / บิวอินสำหรับคอมไพเลอร์หลักที่ต้องการ)
อยู่ที่ไหนMIN
และMAX
กำหนดไว้ใน C ถ้าทั้งหมด?
เป็นวิธีที่ดีที่สุดในการใช้สิ่งเหล่านี้โดยทั่วไปและพิมพ์อย่างปลอดภัยที่สุดเท่าที่จะทำได้? (ส่วนขยายคอมไพเลอร์ / บิวอินสำหรับคอมไพเลอร์หลักที่ต้องการ)
คำตอบ:
อยู่ที่ไหน
MIN
และMAX
กำหนดไว้ใน C ถ้าทั้งหมด?
พวกเขาไม่ได้
เป็นวิธีที่ดีที่สุดในการใช้สิ่งเหล่านี้โดยทั่วไปและพิมพ์ปลอดภัยที่สุดเท่าที่จะทำได้ (ส่วนขยายคอมไพเลอร์ / บิวด์สำหรับคอมไพเลอร์หลักที่ต้องการ)
เป็นฟังก์ชั่น ฉันจะไม่ใช้แมโคร#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
โดยเฉพาะอย่างยิ่งหากคุณวางแผนที่จะปรับใช้รหัสของคุณ ไม่ว่าจะเป็นการเขียนของคุณเองใช้สิ่งที่เป็นมาตรฐานfmax
หรือfmin
แก้ไขแมโครโดยใช้typeof ของ GCC (คุณจะได้รับโบนัสความปลอดภัยมากเกินไป) ในการแสดงออกของคำสั่ง GCC :
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
ทุกคนพูดว่า "โอ้ฉันรู้เกี่ยวกับการประเมินสองครั้งไม่มีปัญหา" และไม่กี่เดือนตามถนนคุณจะได้รับการแก้ไขปัญหาที่โง่ที่สุดสำหรับชั่วโมงที่สิ้นสุด
หมายเหตุการใช้งาน__typeof__
แทนtypeof
:
ถ้าคุณเขียนไฟล์ส่วนหัวว่าการทำงานต้องเมื่อรวมอยู่ในโปรแกรม ISO C, เขียนแทน
__typeof__
typeof
decltype
คำหลักใหม่ MSVC ++ 2010 - แต่ถึงกระนั้น Visual Studio ไม่สามารถทำงบผสมในมาโครได้ (และdecltype
คือ C ++ ต่อไป) นั่นคือ({ ... })
ไวยากรณ์ของ GCC ดังนั้นฉันค่อนข้างแน่ใจว่ามันเป็นไปไม่ได้ ฉันไม่ได้ดูคอมไพเลอร์อื่น ๆ เกี่ยวกับปัญหานี้ขอโทษ Luther: S
MAX(someUpperBound, someRandomFunction())
เพื่อ จำกัด ค่าการสุ่มที่ขอบเขตบน มันเป็นความคิดที่แย่มาก แต่ก็ไม่ได้ผลเพราะMAX
เขาใช้มีปัญหาในการประเมินสองครั้งดังนั้นเขาจึงสิ้นสุดด้วยตัวเลขสุ่มที่แตกต่างจากที่ประเมินในตอนแรก
MIN(x++, y++)
preprocessor (((x++) < (y++)) ? (x++) : (y++))
จะสร้างรหัสต่อไปนี้ ดังนั้นx
และy
จะเพิ่มขึ้นสองครั้ง
มันมีให้ใน GNU libc (Linux) และ FreeBSD เวอร์ชัน sys / param.h และมีคำจำกัดความของ Dreamlax
บนเดเบียน:
$ uname -sr
Linux 2.6.11
$ cat /etc/debian_version
5.0.2
$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
$ head -n 2 /usr/include/sys/param.h | grep GNU
This file is part of the GNU C Library.
ใน FreeBSD:
$ uname -sr
FreeBSD 5.5-STABLE
$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
แหล่งเก็บข้อมูลต้นฉบับอยู่ที่นี่:
openSUSE/Linux 3.1.0-1.2-desktop
/ gcc version 4.6.2 (SUSE Linux)
เกินไป :) ไม่ดีเลยมันพกพาไม่ได้
มีstd::min
และstd::max
ใน C ++ แต่ AFAIK ไม่มีอะไรเทียบเท่าในไลบรารีมาตรฐาน C คุณสามารถกำหนดได้ด้วยตนเองเช่นมาโคร
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
MAX(++a, ++b)
แต่นี้ทำให้เกิดปัญหาถ้าคุณเขียนสิ่งที่ต้องการ
#define MIN(A, B) ((A < B) ? A : B)
ไม่ใช่วิธีที่ยืดหยุ่นทำไม ???
#define MULT(x, y) x * y
ตัวอย่างเช่นพิจารณา จากนั้นMULT(a + b, a + b)
ขยายไปa + b * a + b
ซึ่งแยกวิเคราะห์ตามa + (b * a) + b
ความสำคัญ นั่นไม่ใช่สิ่งที่โปรแกรมเมอร์ตั้งใจไว้
หลีกเลี่ยงส่วนขยายคอมไพเลอร์ที่ไม่ได้มาตรฐานและใช้มันเป็นมาโครประเภทที่ปลอดภัยอย่างสมบูรณ์ในมาตรฐาน C บริสุทธิ์ (ISO 9899: 2011)
สารละลาย
#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))
#define ENSURE_int(i) _Generic((i), int: (i))
#define ENSURE_float(f) _Generic((f), float: (f))
#define MAX(type, x, y) \
(type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))
การใช้
MAX(int, 2, 3)
คำอธิบาย
แมโคร MAX สร้างมาโครอื่นตามtype
พารามิเตอร์ มาโครควบคุมนี้หากใช้กับประเภทที่กำหนดจะใช้เพื่อตรวจสอบว่าพารามิเตอร์ทั้งสองเป็นประเภทที่ถูกต้อง หากว่าtype
ไม่รองรับจะมีข้อผิดพลาดคอมไพเลอร์
หาก x หรือ y ไม่ได้เป็นประเภทที่ถูกต้องจะมีข้อผิดพลาดคอมไพเลอร์ใน ENSURE_
มาโคร สามารถเพิ่มมาโครได้เช่นนี้หากรองรับประเภทเพิ่มเติม ฉันคิดว่าจะใช้เฉพาะเลขคณิต (จำนวนเต็มลอยตัวชี้ ฯลฯ ) เท่านั้นและจะไม่ใช้ structs หรืออาร์เรย์เป็นต้น
หากทุกประเภทถูกต้องจะมีการเรียกมาโคร GENERIC_MAX วงเล็บเพิ่มเติมจำเป็นต้องมีรอบพารามิเตอร์มาโครแต่ละตัวซึ่งเป็นข้อควรระวังมาตรฐานทั่วไปเมื่อเขียนมาโคร C
จากนั้นมีปัญหาตามปกติกับการส่งเสริมการพิมพ์โดยนัยในซี?:
โอเปอเรเตอร์สมดุลตัวถูกดำเนินการที่ 2 และ 3 กับแต่ละอื่น ๆ ตัวอย่างเช่นผลมาจากการจะเป็นGENERIC_MAX(my_char1, my_char2)
int
เพื่อป้องกันไม่ให้แมโครทำการส่งเสริมประเภทที่อาจเป็นอันตรายดังกล่าวจึงใช้ตัวเลือกประเภทสุดท้ายไปยังประเภทที่ต้องการ
หลักการและเหตุผล
เราต้องการให้พารามิเตอร์ทั้งสองเป็นมาโครเป็นประเภทเดียวกัน หากหนึ่งในนั้นเป็นประเภทที่แตกต่างกันแมโครจะไม่ปลอดภัยอีกต่อไปเพราะผู้ดำเนินการที่ชอบ?:
จะให้การส่งเสริมการพิมพ์โดยนัย และเนื่องจากเป็นเช่นนั้นเราจำเป็นต้องส่งผลลัพธ์สุดท้ายกลับไปยังประเภทเป้าหมายตามที่อธิบายไว้ข้างต้น
แมโครที่มีพารามิเตอร์เพียงตัวเดียวสามารถเขียนด้วยวิธีที่ง่ายกว่ามาก แต่ด้วยพารามิเตอร์ 2 พารามิเตอร์ขึ้นไปจำเป็นต้องมีพารามิเตอร์ชนิดพิเศษ เพราะสิ่งนี้เป็นไปไม่ได้เลย:
// this won't work
#define MAX(x, y) \
_Generic((x), \
int: GENERIC_MAX(x, ENSURE_int(y)) \
float: GENERIC_MAX(x, ENSURE_float(y)) \
)
ปัญหาคือว่าถ้าแมโคด้านบนถูกเรียกเช่นเดียวMAX(1, 2)
กับสองint
มันจะยังคงพยายามที่จะขยายสถานการณ์จำลองที่เป็นไปได้ทั้งหมดของ_Generic
รายการการเชื่อมโยง ดังนั้นENSURE_float
แมโครจะขยายตัวเช่นกันแม้ว่าจะไม่เกี่ยวข้องint
กัน และเนื่องจากแมโครนั้นมีเพียงfloat
ชนิดเท่านั้นโดยเจตนารหัสจะไม่รวบรวม
ในการแก้ปัญหานี้ฉันได้สร้างชื่อมาโครในระหว่างตัวประมวลผลล่วงหน้าแทนด้วยตัวดำเนินการ ## เพื่อไม่ให้แมโครขยายตัวโดยไม่ตั้งใจ
ตัวอย่าง
#include <stdio.h>
#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))
#define ENSURE_int(i) _Generic((i), int: (i))
#define ENSURE_float(f) _Generic((f), float: (f))
#define MAX(type, x, y) \
(type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))
int main (void)
{
int ia = 1, ib = 2;
float fa = 3.0f, fb = 4.0f;
double da = 5.0, db = 6.0;
printf("%d\n", MAX(int, ia, ib)); // ok
printf("%f\n", MAX(float, fa, fb)); // ok
//printf("%d\n", MAX(int, ia, fa)); compiler error, one of the types is wrong
//printf("%f\n", MAX(float, fa, ib)); compiler error, one of the types is wrong
//printf("%f\n", MAX(double, fa, fb)); compiler error, the specified type is wrong
//printf("%f\n", MAX(float, da, db)); compiler error, one of the types is wrong
//printf("%d\n", MAX(unsigned int, ia, ib)); // wont get away with this either
//printf("%d\n", MAX(int32_t, ia, ib)); // wont get away with this either
return 0;
}
GENERIC_MAX
แมโครเป็นความคิดที่ไม่ดีโดยวิธีการที่คุณจะต้องพยายามที่GENERIC_MAX(var++, 7)
จะหาว่าทำไม :-) ปัจจุบัน (โดยเฉพาะอย่างยิ่งกับการเพิ่มประสิทธิภาพอย่างหนัก / inlining คอมไพเลอร์) แมโครควรจะสวยมากถูกผลักไสให้ไปในรูปแบบที่ง่ายเท่านั้น ฟังก์ชั่นที่คล้ายฟังก์ชั่นจะดีกว่าฟังก์ชั่นและกลุ่มของค่าที่ดีกว่าสำหรับการแจกแจง
ฉันไม่คิดว่ามันเป็นมาโครมาตรฐาน มีฟังก์ชั่นที่ได้มาตรฐานสำหรับจุดลอยตัวอยู่แล้วfmax
และfmin
(และfmaxf
สำหรับลอยตัวและfmaxl
สำหรับคู่ยาว)
คุณสามารถนำมาใช้เป็นมาโครตราบใดที่คุณตระหนักถึงปัญหาของผลข้างเคียง / การประเมินสองครั้ง
#define MAX(a,b) ((a) > (b) ? a : b)
#define MIN(a,b) ((a) < (b) ? a : b)
ในกรณีส่วนใหญ่คุณสามารถปล่อยให้คอมไพเลอร์เพื่อกำหนดสิ่งที่คุณกำลังพยายามทำและปรับให้เหมาะสมที่สุดเท่าที่จะทำได้ ในขณะที่สิ่งนี้ทำให้เกิดปัญหาเมื่อใช้เช่นMAX(i++, j++)
ฉันสงสัยว่ามีความจำเป็นมากในการตรวจสอบค่าสูงสุดที่เพิ่มขึ้นในครั้งเดียว เพิ่มค่าก่อนจากนั้นตรวจสอบ
นี่คือคำตอบที่ล่าช้าเนื่องจากการพัฒนาที่ค่อนข้างล่าสุด ตั้งแต่ OP ได้รับการยอมรับคำตอบที่อาศัยใน GCC ไม่ใช่แบบพกพา (และเสียงดังกราว) นามสกุลtypeof
- หรือ__typeof__
สำหรับ 'สะอาด' ISO C - มีทางออกที่ดีกว่าที่มีอยู่เป็นของGCC-4.9
#define max(x,y) ( \
{ __auto_type __x = (x); __auto_type __y = (y); \
__x > __y ? __x : __y; })
ประโยชน์ที่ชัดเจนของส่วนขยายนี้คืออาร์กิวเมนต์แมโครแต่ละตัวจะถูกขยายเพียงครั้งเดียวซึ่งแตกต่างจาก__typeof__
โซลูชัน
__auto_type
เป็นรูปแบบที่ จำกัด auto
ของภาษา C ไม่สามารถใช้ (หรือไม่ควร?) ในรหัส C ++ แม้ว่าจะไม่มีเหตุผลที่ดีที่จะไม่ใช้ความสามารถในการอนุมานประเภทที่เหนือกว่าauto
เมื่อใช้ C ++ 11
ที่กล่าวว่าฉันคิดว่าไม่มีปัญหาในการใช้ไวยากรณ์นี้เมื่อแมโครรวมอยู่ในextern "C" { ... }
ขอบเขต เช่นจากส่วนหัว C AFAIK ส่วนขยายนี้ไม่พบวิธีที่เสียงดังกังวาน
c-preprocessor
แท็ก ฟังก์ชั่นไม่ได้รับการรับประกันว่าจะถูกขีดเส้นใต้แม้จะมีคำหลักที่กล่าวถึงเว้นแต่ใช้สิ่งที่ต้องการ__always_inline__
คุณลักษณะของ gcc
ฉันเขียนเวอร์ชันนี้ที่ใช้งานได้กับ MSVC, GCC, C และ C ++
#if defined(__cplusplus) && !defined(__GNUC__)
# include <algorithm>
# define MIN std::min
# define MAX std::max
//# define TMIN(T, a, b) std::min<T>(a, b)
//# define TMAX(T, a, b) std::max<T>(a, b)
#else
# define _CHOOSE2(binoper, lexpr, lvar, rexpr, rvar) \
({ \
decltype(lexpr) lvar = (lexpr); \
decltype(rexpr) rvar = (rexpr); \
lvar binoper rvar ? lvar : rvar; \
})
# define _CHOOSE_VAR2(prefix, unique) prefix##unique
# define _CHOOSE_VAR(prefix, unique) _CHOOSE_VAR2(prefix, unique)
# define _CHOOSE(binoper, lexpr, rexpr) \
_CHOOSE2( \
binoper, \
lexpr, _CHOOSE_VAR(_left, __COUNTER__), \
rexpr, _CHOOSE_VAR(_right, __COUNTER__) \
)
# define MIN(a, b) _CHOOSE(<, a, b)
# define MAX(a, b) _CHOOSE(>, a, b)
#endif
หากคุณต้องการขั้นต่ำ / สูงสุดเพื่อหลีกเลี่ยงสาขาที่มีราคาแพงคุณไม่ควรใช้ผู้ประกอบการที่ประกอบไปด้วยไตรภาค ลิงค์ด้านล่างอธิบายถึงวิธีการที่มีประโยชน์สำหรับการใช้ฟังก์ชั่นขั้นต่ำ / สูงสุดโดยไม่ต้องแยกสาขา
http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
@ David Titarenco จับที่นี่แต่อย่างน้อยให้ฉันทำความสะอาดเล็กน้อยเพื่อให้ดูดีและแสดงทั้งสองmin()
และ max()
ร่วมกันเพื่อให้การคัดลอกและวางจากที่นี่ง่ายขึ้น :)
อัปเดต 25 เม.ย. 2563: ฉันได้เพิ่มส่วนที่ 3 เพื่อแสดงว่าจะทำอย่างไรกับเทมเพลต C ++ เช่นกันเพื่อเป็นการเปรียบเทียบที่มีค่าสำหรับการเรียนรู้ทั้ง C และ C ++ หรือการเปลี่ยนจากที่หนึ่งไปยังอีกที่หนึ่ง ฉันพยายามทำให้ดีที่สุดเพื่อให้ละเอียดถี่ถ้วนและเป็นจริงและถูกต้องเพื่อให้คำตอบนี้เป็นข้อมูลอ้างอิงที่เป็นที่ยอมรับฉันสามารถกลับมาอีกครั้งและอีกครั้งและฉันหวังว่าคุณจะพบว่ามันมีประโยชน์เท่าที่ฉันทำได้
เทคนิคนี้เป็นที่นิยมใช้กันอย่างแพร่หลายโดยผู้ที่รู้จักวิธีใช้อย่างถูกต้องวิธีการ "ทำพฤตินัย" และใช้งานได้ดีหากใช้อย่างเหมาะสม แต่เป็นรถม้า (คิดว่า: ผลข้างเคียงแบบประเมินสองครั้ง ) หากคุณ เคยผ่านการแสดงออกรวมถึงการกำหนดตัวแปรในการเปรียบเทียบ:
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
เทคนิคนี้หลีกเลี่ยงผลข้างเคียงและข้อผิดพลาด "การประเมินซ้ำสองครั้ง" และถือว่าเป็นวิธีที่ดีกว่าปลอดภัยกว่าและ "ทันสมัยกว่า" GCC C ในการทำเช่นนี้ คาดว่ามันจะทำงานกับคอมไพเลอร์ gcc และ clang เนื่องจาก clang คือโดยการออกแบบเข้ากันได้กับ gcc (ดูบันทึกย่อเสียงดังที่ด้านล่างของคำตอบนี้)
แต่: ระวังเอฟเฟกต์" ตัวแปรแชโดว์ตัวแปร " เนื่องจากการแสดงออกของคำสั่งจะเห็นได้ชัดเจนและดังนั้นจึงไม่มีขอบเขตตัวแปรท้องถิ่นของตัวเอง!
#define max(a,b) \
({ \
__typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; \
})
#define min(a,b) \
({ \
__typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; \
})
โปรดทราบว่าในนิพจน์คำสั่ง gcc นิพจน์สุดท้ายในบล็อกโค้ดคือสิ่งที่ "คืน" จากนิพจน์ราวกับว่าถูกส่งคืนจากฟังก์ชัน เอกสารของ GCCบอกด้วยวิธีนี้:
สิ่งสุดท้ายในคำสั่งผสมควรเป็นการแสดงออกตามด้วยเครื่องหมายอัฒภาค; ค่าของนิพจน์ย่อยนี้ทำหน้าที่เป็นค่าของการสร้างทั้งหมด (ถ้าคุณใช้คำสั่งชนิดอื่นบางอย่างล่าสุดภายในวงเล็บปีกกาการก่อสร้างมีโมฆะประเภทและจึงไม่มีค่าอย่างมีประสิทธิภาพ)
C ++ หมายเหตุ: ถ้าใช้ C ++, แนะนำให้ใช้เทมเพลตสำหรับการสร้างประเภทนี้แทน แต่ส่วนตัวแล้วฉันไม่ชอบเทมเพลตและอาจใช้หนึ่งในการสร้างข้างต้นใน C ++ ต่อไปเนื่องจากฉันมักจะใช้และชอบสไตล์ C ใน C ++ ฝังตัวด้วยเช่นกัน
ส่วนนี้เพิ่ม 25 เมษายน 2020:
ฉันได้ทำ C ++ มาหลายเดือนแล้วและความกดดันในการเลือกเทมเพลตมากกว่ามาโครที่สามารถทำได้ในชุมชน C ++ นั้นค่อนข้างแข็งแกร่ง ด้วยเหตุนี้ฉันจึงเริ่มใช้เทมเพลตได้ดีขึ้นและต้องการวางเทมเพลตรุ่น C ++ ที่นี่เพื่อความสมบูรณ์และเพื่อทำให้คำตอบนี้เป็นที่ยอมรับและทั่วถึงมากขึ้น
นี่คือเวอร์ชันเทมเพลตฟังก์ชันพื้นฐานmax()
และmin()
อาจมีลักษณะเป็นใน C ++:
template <typename T>
T max(T a, T b)
{
return a > b ? a : b;
}
template <typename T>
T min(T a, T b)
{
return a < b ? a : b;
}
ทำอ่านเพิ่มเติมเกี่ยวกับ C ++ แม่แบบที่นี่: วิกิพีเดีย: แม่แบบ (C ++)
อย่างไรก็ตามทั้งสองmax()
และmin()
เป็นส่วนหนึ่งของไลบรารีมาตรฐาน C ++ แล้วใน<algorithm>
ส่วนหัว ( #include <algorithm>
) ในไลบรารีมาตรฐาน C ++ พวกเขาถูกกำหนดแตกต่างจากที่ฉันมีไว้ด้านบนเล็กน้อย ต้นแบบเริ่มต้นสำหรับstd::max<>()
และstd::min<>()
ตัวอย่างเช่นใน C ++ 14 ดูที่ต้นแบบในลิงค์ cplusplus.com ด้านบนคือ:
template <class T>
constexpr const T& max(const T& a, const T& b);
template <class T>
constexpr const T& min(const T& a, const T& b);
หมายเหตุว่าคำหลักtypename
เป็นนามแฝงไปclass
(เพื่อให้การใช้งานของพวกเขาเป็นเหมือนกันไม่ว่าคุณจะพูด<typename T>
หรือ<class T>
) เนื่องจากมันได้รับการยอมรับต่อมาหลังจากการประดิษฐ์ของ C ++ แม่แบบว่าประเภทแม่แบบอาจจะเป็นประเภททั่วไป ( int
, float
ฯลฯ ) แทนที่จะเป็นเพียง ประเภทชั้นเรียน
ที่นี่คุณจะเห็นได้ว่าทั้งสองประเภทอินพุตเช่นเดียวกับประเภทกลับเป็นconst T&
ซึ่งหมายถึง "การอ้างอิงคงที่เพื่อพิมพ์T
" วิธีนี้ป้อนพารามิเตอร์และค่าตอบแทนจะผ่านอ้างอิงแทนการผ่านค่า นี่เป็นเหมือนการส่งผ่านพอยน์เตอร์และมีประสิทธิภาพมากขึ้นสำหรับประเภทขนาดใหญ่เช่นคลาสอ็อบเจ็กต์ constexpr
ส่วนหนึ่งของฟังก์ชั่นปรับเปลี่ยนฟังก์ชั่นของตัวเองและแสดงให้เห็นว่าการทำงานจะต้องมีความสามารถในการประเมินที่รวบรวมเวลา (อย่างน้อยถ้าให้constexpr
ป้อนพารามิเตอร์) แต่ถ้ามันไม่สามารถได้รับการประเมินที่รวบรวมเวลาแล้วค่าเริ่มต้นกลับไป การประเมินเวลาทำงานเหมือนกับฟังก์ชั่นปกติอื่น ๆ
มุมมองเวลาคอมไพล์ของconstexpr
ฟังก์ชัน C ++ ทำให้เป็นแบบ C-macro-like ซึ่งถ้าการประเมินเวลาคอมไพล์เป็นไปได้สำหรับconstexpr
ฟังก์ชั่นมันจะทำที่รวบรวมเวลาเช่นเดียวกับการแทนที่แมโครMIN()
หรือMAX()
อาจเป็นไปได้ ได้รับการประเมินอย่างสมบูรณ์ที่รวบรวมเวลาใน C หรือ C ++ เกินไป สำหรับการอ้างอิงเพิ่มเติมสำหรับข้อมูลเทมเพลต C ++ นี้ดูด้านล่าง
เสียงดังกราวจาก Wikipedia :
[Clang] ได้รับการออกแบบมาเพื่อทำหน้าที่แทนการแทนที่สำหรับ GNU Compiler Collection (GCC) ซึ่งสนับสนุนการรวบรวมส่วนใหญ่ของแฟล็กการรวบรวมและส่วนขยายภาษาที่ไม่เป็นทางการ
มันคุ้มค่าที่จะชี้ให้เห็นว่าฉันคิดว่าถ้าคุณกำหนดmin
และmax
กับระดับอุดมศึกษาเช่น
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
จากนั้นจะได้ผลลัพธ์เดียวกันสำหรับกรณีพิเศษfmin(-0.0,0.0)
และfmax(-0.0,0.0)
คุณต้องสลับอาร์กิวเมนต์
fmax(a,b) = MAX(a,b)
fmin(a,b) = MIN(b,a)
fmin(3.0,NaN)==fmin(NaN,3.0)==fmax(3.0,NaN)==fmax(NaN,3.0)==3.0
ดูเหมือนว่าWindef.h
(a la #include <windows.h>
) มีmax
และmin
(ตัวพิมพ์เล็ก) มาโครที่ยังประสบกับความยากลำบาก "การประเมินสองครั้ง" แต่พวกเขาอยู่ที่นั่นสำหรับผู้ที่ไม่ต้องการม้วนตัวเอง :)
ฉันรู้ว่าคนที่แต่งตัวประหลาดพูดว่า "C" ... แต่ถ้าคุณมีโอกาสให้ใช้เทมเพลต C ++:
template<class T> T min(T a, T b) { return a < b ? a : b; }
พิมพ์ปลอดภัยและไม่มีปัญหากับ ++ ที่กล่าวถึงในความคิดเห็นอื่น
สูงสุดของทั้งสองจำนวนเต็มa
และมีb
(int)(0.5((a+b)+abs(a-b)))
สิ่งนี้อาจทำงานร่วมกับ(double)
และfabs(a-b)
สำหรับคู่ผสม (คล้ายกับลอย)
วิธีที่ง่ายที่สุดคือการกำหนดให้เป็นฟังก์ชั่นระดับโลกใน.h
ไฟล์และเรียกมันเมื่อใดก็ตามที่คุณต้องการหากโปรแกรมของคุณเป็นโมดูลที่มีไฟล์จำนวนมาก ถ้าไม่double MIN(a,b){return (a<b?a:b)}
เป็นวิธีที่ง่ายที่สุด
warning: expression with side-effects multiply evaluated by macro
ณ จุดใช้ ...