MIN và MAX trong C


300

Ở đâu MINMAXđược định nghĩa trong C, nếu có?

Cách tốt nhất để thực hiện những điều này, một cách khái quát và gõ an toàn nhất có thể là gì? (Tiện ích mở rộng trình biên dịch / nội dung cho trình biên dịch chính được ưa thích.)

Câu trả lời:


392

Ở đâu MINMAXđược định nghĩa trong C, nếu có?

Họ không.

Cách tốt nhất để thực hiện những điều này là gì, nói chung và gõ an toàn nhất có thể (phần mở rộng / phần mềm biên dịch cho trình biên dịch chính được ưa thích).

Là chức năng. Tôi sẽ không sử dụng các macro như thế #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)), đặc biệt nếu bạn dự định triển khai mã của mình. Hoặc tự viết, sử dụng một cái gì đó như tiêu chuẩn fmaxhoặc fminsửa lỗi macro bằng cách sử dụng loại của GCC (bạn cũng nhận được phần thưởng an toàn kiểu) trong biểu thức tuyên bố GCC :

 #define max(a,b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a > _b ? _a : _b; })

Mọi người đều nói "ồ tôi biết về đánh giá kép, không vấn đề gì" và vài tháng sau, bạn sẽ gỡ lỗi cho những vấn đề khó hiểu nhất trong nhiều giờ liền.

Lưu ý việc sử dụng __typeof__thay vì typeof:

Nếu bạn đang viết một tệp tiêu đề phải hoạt động khi được bao gồm trong các chương trình ISO C, hãy viết __typeof__thay vì typeof.


68
Bạn biết đấy, sẽ khá tiện nếu gcc có cảnh báo dọc theo dòng: warning: expression with side-effects multiply evaluated by macrotại điểm sử dụng ...
caf

23
@caf: không yêu cầu bộ tiền xử lý có kiến ​​thức phức tạp hơn về cú pháp C?
dreamlax

3
Sau khi cố gắng tìm hiểu, tôi không nghĩ có cách nào để làm điều này trong VC ++, nhưng tốt nhất của bạn là cố gắng làm rối với decltypetừ khóa mới MSVC ++ 2010 - nhưng ngay cả như vậy, Visual Studio không thể thực hiện các câu lệnh ghép trong macro (và decltypedù sao cũng là C ++), tức là ({ ... })cú pháp của GCC nên tôi chắc chắn rằng điều đó là không thể. Tôi đã không xem xét bất kỳ trình biên dịch nào khác liên quan đến vấn đề này, xin lỗi Luther: S
David Titarenco

7
@dreamlax Tôi đã từng thấy một trường hợp ai đó đã làm MAX(someUpperBound, someRandomFunction()) để giới hạn một giá trị ngẫu nhiên ở một số giới hạn trên. Đó là một ý tưởng tồi tệ, nhưng nó thậm chí còn không hiệu quả, bởi vì MAXanh ta đang sử dụng có vấn đề đánh giá kép, vì vậy anh ta kết thúc với một số ngẫu nhiên khác với số được đánh giá ban đầu.
Zev Eisenberg

8
@Soumen Ví dụ: nếu bạn gọi MIN(x++, y++)bộ tiền xử lý sẽ tạo mã sau (((x++) < (y++)) ? (x++) : (y++)). Vì vậy, xy sẽ được tăng lên hai lần.
Antonio

91

Nó cũng được cung cấp trong các phiên bản GNU libc (Linux) và FreeBSD của sys / param.h và có định nghĩa được cung cấp bởi dreamlax.


Trên Debian:

$ 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.

Trên 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))

Các kho lưu trữ nguồn ở đây:


Tôi đã thêm các định nghĩa từ các hệ thống mà tôi có quyền truy cập vào câu trả lời của mình ở trên (trường nhận xét không chấp nhận định dạng theo như tôi có thể nói). Sẽ cố gắng tìm các liên kết đến repos nguồn FreeBSD / Linux / glibc.
Mikel

+1. Rất đẹp. Hoạt động cho openSUSE/Linux 3.1.0-1.2-desktop/ gcc version 4.6.2 (SUSE Linux) quá. :) Thật không thể di động.
Jack

Hoạt động trên Cygwin cũng vậy.
CMCDragonkai

1
Đợi một chút. Nó không ngăn chặn đánh giá kép, phải không? : 3
dùng1857492

76

Có một std::minstd::maxtrong C ++, nhưng AFAIK, không có thư viện chuẩn C nào tương đương. Bạn có thể tự xác định chúng bằng các macro như

#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))

Nhưng điều này gây ra vấn đề nếu bạn viết một cái gì đó như MAX(++a, ++b).


10
Tại sao đặt quá nhiều dấu ngoặc ??? Tôi tìm thấy một bài kiểm tra mà họ nói #define MIN(A, B) ((A < B) ? A : B)không phải là một cách linh hoạt, tại sao ???

78
@Makouda: Dấu ngoặc đơn bổ sung trong macro giúp tránh các vấn đề ưu tiên của nhà điều hành. Ví dụ, xem xét #define MULT(x, y) x * y. Sau đó MULT(a + b, a + b)mở rộng đến a + b * a + b, phân tích cú pháp a + (b * a) + bdo ưu tiên. Đó không phải là những gì lập trình viên có thể dự định.
dan04

không cần thiết khi nào ?: dù sao cũng có quyền ưu tiên thấp nhất
Cầu thủ chạy cánh Sendon

@WingerSendon: Nó không; toán tử dấu phẩy không.
dan04

24

Tránh các phần mở rộng trình biên dịch không chuẩn và triển khai nó dưới dạng macro hoàn toàn an toàn loại trong tiêu chuẩn thuần C (ISO 9899: 2011).

Giải pháp

#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))

Sử dụng

MAX(int, 2, 3)

Giải trình

Macro MAX tạo một macro khác dựa trên typetham số. Macro điều khiển này, nếu được triển khai cho loại đã cho, được sử dụng để kiểm tra cả hai tham số có đúng loại không. Nếutype không được hỗ trợ, sẽ có lỗi trình biên dịch.

Nếu x hoặc y không đúng loại, sẽ có lỗi trình biên dịch trong ENSURE_ macro. Nhiều macro như vậy có thể được thêm vào nếu nhiều loại được hỗ trợ. Tôi đã giả định rằng chỉ các loại số học (số nguyên, số float, con trỏ, v.v.) sẽ được sử dụng và không sử dụng cấu trúc hoặc mảng, v.v.

Nếu tất cả các loại đều đúng, macro GENERIC_MAX sẽ được gọi. Cần có dấu ngoặc đơn xung quanh mỗi tham số macro, như biện pháp phòng ngừa tiêu chuẩn thông thường khi viết macro C.

Sau đó, có các vấn đề thông thường với các chương trình khuyến mãi ngầm định trong C. Nhà ?:điều hành cân bằng toán hạng thứ 2 và thứ 3 với nhau. Ví dụ: kết quả của GENERIC_MAX(my_char1, my_char2)sẽ là mộtint . Để ngăn macro thực hiện các quảng cáo loại nguy hiểm tiềm tàng như vậy, loại cuối cùng được sử dụng cho loại dự định đã được sử dụng.

Cơ sở lý luận

Chúng tôi muốn cả hai tham số cho macro là cùng loại. Nếu một trong số chúng thuộc loại khác, macro không còn là loại an toàn, bởi vì một toán tử thích?: sẽ mang lại các chương trình khuyến mãi kiểu ngầm. Và bởi vì nó, chúng ta cũng luôn cần đưa kết quả cuối cùng trở lại loại dự định như đã giải thích ở trên.

Một macro chỉ với một tham số có thể đã được viết theo cách đơn giản hơn nhiều. Nhưng với 2 tham số trở lên, cần bao gồm một tham số loại phụ. Bởi vì điều này thật không may là không thể:

// this won't work
#define MAX(x, y)                                  \
  _Generic((x),                                    \
           int: GENERIC_MAX(x, ENSURE_int(y))      \
           float: GENERIC_MAX(x, ENSURE_float(y))  \
          )

Vấn đề là nếu macro ở trên được gọi là MAX(1, 2)với hai int, nó vẫn sẽ cố gắng mở rộng macro tất cả các kịch bản có thể có của _Genericdanh sách liên kết. Vì vậy, ENSURE_floatmacro cũng sẽ được mở rộng, mặc dù nó không liên quan int. Và vì macro cố ý chỉ chứa floatloại, mã sẽ không được biên dịch.

Để giải quyết điều này, tôi đã tạo tên macro trong giai đoạn tiền xử lý thay vào đó, với toán tử ##, để không có macro nào vô tình được mở rộng.

Ví dụ

#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;
}

Nhân tiện, GENERIC_MAXmacro đó là một ý tưởng tồi, bạn chỉ phải cố gắng GENERIC_MAX(var++, 7)tìm hiểu lý do tại sao :-) Ngày nay (đặc biệt là với trình biên dịch tối ưu hóa / nội tuyến rất nhiều), các macro chỉ nên được chuyển sang các dạng đơn giản. Các hàm giống như hàm tốt hơn là hàm và nhóm giá trị tốt hơn khi liệt kê.
paxdiablo

21

Tôi không nghĩ rằng chúng là các macro được tiêu chuẩn hóa. Có các chức năng được tiêu chuẩn hóa cho điểm nổi đã có, fmaxfmin(và fmaxfcho phao và fmaxlcho đôi dài).

Bạn có thể triển khai chúng dưới dạng macro miễn là bạn nhận thức được các vấn đề về tác dụng phụ / đánh giá kép.

#define MAX(a,b) ((a) > (b) ? a : b)
#define MIN(a,b) ((a) < (b) ? a : b)

Trong hầu hết các trường hợp, bạn có thể để nó cho trình biên dịch để xác định những gì bạn đang cố gắng làm và tối ưu hóa nó tốt nhất có thể. Mặc dù điều này gây ra vấn đề khi được sử dụng như thế nào MAX(i++, j++), tôi nghi ngờ sẽ có rất nhiều nhu cầu trong việc kiểm tra tối đa các giá trị gia tăng trong một lần. Tăng trước, sau đó kiểm tra.


Điều này sẽ là câu trả lời ưa thích vì có rõ ràng là min và max chức năng trong thư viện toán học: cplusplus.com/reference/cmath/fmax
imranal

@imranal Bạn đang nói chính xác về cái gì? Các thực hiện quy tắc ứng những thư viện? Nhưng mã đó không bị lộ , tức là họ không đặt nó trong giao diện của thư viện, có khả năng không an toàn.
Antonio

@Antonio Tôi nghĩ rằng bạn đang sử dụng các định nghĩa không chính xác về "tiếp xúc" và "giao diện". Giao diện của thư viện ac là các biến, kiểu, macro và khai báo hàm bên ngoài trong một tệp tiêu đề; fmin / fmax được khai báo trong tệp tiêu đề, vì vậy chúng được cho là bị lộ. Tôi không chắc chắn những gì bạn đang đề cập đến là không an toàn mặc dù.
hợp lý

21

Đây là một câu trả lời muộn, do một sự phát triển khá gần đây. Vì OP đã chấp nhận câu trả lời dựa trên phần mở rộng GCC (và clang) không di động typeof- hoặc __typeof__cho 'C' sạch '- nên có một giải pháp tốt hơn có sẵn từ gcc-4.9 .

#define max(x,y) ( \
    { __auto_type __x = (x); __auto_type __y = (y); \
      __x > __y ? __x : __y; })

Lợi ích rõ ràng của phần mở rộng này là mỗi đối số macro chỉ được mở rộng một lần, không giống như __typeof__giải pháp.

__auto_typelà một dạng hạn chế của C ++ 11's auto. Nó không thể (hoặc không nên?) Được sử dụng trong mã C ++, mặc dù không có lý do chính đáng nào để không sử dụng các khả năng suy luận loại ưu việt củaauto khi sử dụng C ++ 11.

Điều đó nói rằng, tôi cho rằng không có vấn đề gì khi sử dụng cú pháp này khi macro được bao gồm trong một extern "C" { ... }phạm vi; ví dụ: từ một tiêu đề C. AFAIK, tiện ích mở rộng này chưa tìm thấy thông tin.


Liên quan đến nhận xét của Brett Hale , clangbắt đầu hỗ trợ __auto_typevào khoảng năm 2016 (xem bản vá ).
Lars

Kudos để nhận ra vấn đề vĩ mô nhưng tôi vẫn khẳng định rằng một chức năng có thể sẽ tốt hơn :-)
paxdiablo

@paxdiablo - Tôi đồng ý, mặc dù câu hỏi có c-preprocessorthẻ. Một chức năng không được đảm bảo để được nội tuyến ngay cả với từ khóa đã nói, trừ khi sử dụng một cái gì đó như __always_inline__thuộc tính của gcc .
Brett Hale

11

Tôi đã viết phiên bản này hoạt động cho MSVC, GCC, C và 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

Tôi nâng cấp nhưng số nhận dạng bắt đầu bằng dấu gạch dưới theo sau bằng chữ in hoa được bảo lưu.
dreamlax

8

Nếu bạn cần tối thiểu / tối đa để tránh một nhánh đắt tiền, bạn không nên sử dụng toán tử ternary, vì nó sẽ biên dịch thành một bước nhảy. Liên kết dưới đây mô tả một phương pháp hữu ích để thực hiện chức năng tối thiểu / tối đa mà không cần phân nhánh.

http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax


1
Nếu trình biên dịch đủ thông minh, nó có thể tránh được nhánh
Axel Gneiting

2
Nếu tối ưu hóa được bật, tất cả các trình biên dịch hiện đại sẽ phát ra một động thái có điều kiện thay vì một nhánh trong hầu hết các trường hợp, do đó, có rất ít điểm trong việc sử dụng các bản hack như thế này.
Krzysztof Kosiński 10/03/2015

1
Hoàn toàn đúng, tôi không biết tôi đang nhìn lại cái gì, đã lâu rồi. Cả gcc và clang đều tránh các nhánh có -O, cả trên x86 và armv7a.
cib

6

@David Titarenco đóng đinh nó ở đây , nhưng ít nhất hãy để tôi dọn dẹp nó một chút để làm cho nó trông đẹp hơn, và hiển thị cả hai min() max() cùng nhau để sao chép và dán từ đây dễ dàng hơn. :)

Cập nhật ngày 25 tháng 4 năm 2020: Tôi cũng đã thêm Phần 3 để chỉ ra cách thực hiện với các mẫu C ++, như một so sánh có giá trị cho những người học cả C và C ++, hoặc chuyển từ loại này sang loại khác. Tôi đã làm hết sức mình để thấu đáo và thực tế và chính xác để biến câu trả lời này thành một tài liệu tham khảo kinh điển mà tôi có thể quay lại nhiều lần và tôi hy vọng bạn thấy nó hữu ích như tôi.

1. Cách macro C cũ:

Kỹ thuật này được sử dụng phổ biến, được tôn trọng bởi những người biết sử dụng nó đúng cách, cách làm "thực tế" và sử dụng tốt nếu sử dụng đúng cách, nhưng lỗi (nghĩ: tác dụng phụ đánh giá kép ) nếu bạn bao giờ vượt qua các biểu thức bao gồm cả gán biến để so sánh:

#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))

2. Cách " biểu thức câu lệnh " gcc mới và được cải tiến :

Kỹ thuật này tránh được các tác dụng phụ và lỗi "đánh giá kép" ở trên, và do đó được coi là cách GCC C vượt trội, an toàn hơn và "hiện đại hơn" để thực hiện điều này. Mong đợi nó hoạt động với cả trình biên dịch gcc và clang, vì clang, theo thiết kế, tương thích với gcc (xem ghi chú tiếng kêu ở cuối câu trả lời này).

NHƯNG: Đừng coi chừng các hiệu ứng " bóng biến " vẫn còn, vì các biểu thức câu lệnh rõ ràng được nội tuyến và do đó KHÔNG có phạm vi biến cục bộ của riêng chúng!

#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;       \
})

Lưu ý rằng trong các biểu thức câu lệnh gcc, biểu thức cuối cùng trong khối mã là những gì được "trả về" từ biểu thức, như thể nó được trả về từ một hàm. Tài liệu của GCC nói theo cách này:

Điều cuối cùng trong câu lệnh ghép phải là một biểu thức theo sau dấu chấm phẩy; giá trị của biểu hiện phụ này đóng vai trò là giá trị của toàn bộ cấu trúc. (Nếu bạn sử dụng một số loại câu lệnh khác tồn tại trong dấu ngoặc nhọn, cấu trúc có kiểu void và do đó không có giá trị.)

3. Cách mẫu C ++:

C ++ Lưu ý: nếu sử dụng C ++, các mẫu có thể được khuyến nghị cho loại cấu trúc này, nhưng cá nhân tôi không thích các mẫu và có thể sẽ sử dụng một trong các cấu trúc trên trong C ++, vì tôi cũng thường xuyên sử dụng và thích các kiểu C trong nhúng C ++.

Phần này được thêm vào ngày 25 tháng 4 năm 2020:

Tôi đã làm rất nhiều C ++ trong vài tháng qua và áp lực phải thích các mẫu hơn các macro, trong đó có thể, trong cộng đồng C ++ khá mạnh. Kết quả là, tôi đã trở nên tốt hơn trong việc sử dụng các mẫu và muốn đưa vào các phiên bản mẫu C ++ ở đây để hoàn thiện và để làm cho câu trả lời chính xác và kỹ lưỡng hơn này.

Đây là phiên bản mẫu chức năng cơ bản của max()min()có thể trông giống như trong 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 thêm về các mẫu C ++ tại đây: Wikipedia: Mẫu (C ++) .

Tuy nhiên, cả hai max()min()đã là một phần của thư viện chuẩn C ++, trong <algorithm>tiêu đề ( #include <algorithm>). Trong thư viện chuẩn C ++, chúng được định nghĩa hơi khác so với tôi có ở trên. Các nguyên mẫu mặc định cho std::max<>()std::min<>(), ví dụ, trong C ++ 14, xem xét các nguyên mẫu của chúng trong các liên kết cplusplus.com ngay phía trên, là:

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);

Lưu ý rằng các từ khóa typenamelà một bí danh để class(vì vậy việc sử dụng của họ là giống hệt nhau cho dù bạn nói <typename T>hay <class T>), vì nó sau đó đã được thừa nhận sau khi phát minh ra C mẫu ++, rằng kiểu mẫu có thể là một loại thường ( int, float, vv) thay vì chỉ một loại lớp.

Ở đây bạn có thể thấy rằng cả hai loại đầu vào, cũng như loại trả về const T&, có nghĩa là "tham chiếu liên tục đến loại T". Điều này có nghĩa là các tham số đầu vào và giá trị trả về được truyền bằng tham chiếu thay vì truyền qua giá trị . Điều này giống như chuyển qua các con trỏ và hiệu quả hơn đối với các loại lớn, chẳng hạn như các đối tượng lớp. Phần constexprcủa hàm tự sửa đổi hàm và chỉ ra rằng hàm phải có khả năng được đánh giá tại thời gian biên dịch (ít nhất là nếu được cung cấpconstexpr các tham số đầu vào), nhưng nếu nó không thể được đánh giá tại thời gian biên dịch, thì nó sẽ mặc định trở lại đánh giá thời gian chạy, giống như bất kỳ chức năng bình thường khác.

Khía cạnh thời gian biên dịch của hàm constexprC ++ làm cho nó giống kiểu C-macro, trong đó nếu đánh giá thời gian biên dịch có thể cho một constexprhàm, thì nó sẽ được thực hiện tại thời gian biên dịch, giống như một MIN()hoặcMAX() thay vĩ mô có thể có thể cũng được đánh giá đầy đủ tại thời gian biên dịch trong C hoặc C ++. Để tham khảo thêm cho thông tin mẫu C ++ này, xem bên dưới.

Người giới thiệu:

  1. https://gcc.gnu.org/onlinesocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinesocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. MIN và MAX trong C
  4. Tham chiếu mẫu C ++ bổ sung được thêm vào tháng 4 năm 2020:
    1. ***** Wikipedia: Mẫu (C ++) <- Thông tin bổ sung TUYỆT VỜI về các mẫu C ++!
    2. (Câu hỏi và câu trả lời của riêng tôi): Tại sao `constexpr` là một phần của nguyên mẫu mẫu C ++ 14 cho` std :: max () `?
    3. Sự khác biệt giữa `constexpr` và` const`

Clang lưu ý từ Wikipedia :

[Clang] được thiết kế để hoạt động như một sự thay thế thả xuống cho Bộ sưu tập trình biên dịch GNU (GCC), hỗ trợ hầu hết các cờ biên dịch và các phần mở rộng ngôn ngữ không chính thức.


Để downvoter từ 24 giờ qua: tin tốt! Tôi đã xóa phần 4 của tôi, tôi đã thêm vào Phần 3 ngày hôm qua và thay vào đó tôi đã đặt nó ở đây . Bạn có thể đánh giá lại câu trả lời của tôi và đưa ra một câu trả lời nếu bạn muốn, vì tôi đã đưa rất nhiều thông tin tốt vào đó và đã cố gắng hết sức để biến nó thành một câu trả lời chính xác, hữu ích, có lợi cho tất cả. Bây giờ trở lại để được tập trung. :) Cảm ơn!
Gabriel Staples

4

Thật đáng để chỉ ra Tôi nghĩ rằng nếu bạn xác định minmaxvới đại học như

#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

sau đó để có được kết quả tương tự cho trường hợp đặc biệt fmin(-0.0,0.0)fmax(-0.0,0.0)bạn cần trao đổi các đối số

fmax(a,b) = MAX(a,b)
fmin(a,b) = MIN(b,a)

Vẫn không làm việc cho NaN. fmin(3.0,NaN)==fmin(NaN,3.0)==fmax(3.0,NaN)==fmax(NaN,3.0)==3.0
greggo

@greggo, tôi đã trả lời tốt hơn ở đây stackoverflow.com/a/30915238/2542702
Z boson

4

Có vẻ như Windef.h(a la #include <windows.h>) có maxmin(chữ thường) macro, cũng gặp phải khó khăn "đánh giá kép", nhưng chúng ở đó cho những người không muốn tự cuộn lại :)


12
Bạn có ngạc nhiên không?
Matt Joiner

2

Tôi biết anh chàng nói "C" ... Nhưng nếu bạn có cơ hội, hãy sử dụng mẫu C ++:

template<class T> T min(T a, T b) { return a < b ? a : b; }

Nhập an toàn và không có vấn đề với ++ được đề cập trong các bình luận khác.


16
Đối số nên là tài liệu tham khảo const, bạn không bao giờ biết những gì người dùng sẽ vượt qua.
nmikhailov

6
Một chức năng như vậy đã được chuẩn hóa ( std :: min ).
dreamlax

C ++ có rất nhiều chức năng tiêu chuẩn cho hầu hết các mục đích thông thường, không phát minh lại bánh xe. Tuy nhiên, MS cũng xác định tối thiểu / tối đa của riêng họ đôi khi gây ra sự cố
phuclv

0

Tối đa của hai số nguyên ab(int)(0.5((a+b)+abs(a-b))). Điều này cũng có thể làm việc với (double)fabs(a-b)cho đôi (tương tự cho phao)


Xin lỗi nếu điều này là sai, tôi là người mới bắt đầu C nhưng mã này hoạt động với tôi
NRZ

2
Tôi không chắc chắn nó hoạt động với số nguyên không. Toán học dấu phẩy động có độ chính xác phi tuyến.
Cây xanh14

Để mở rộng nhận xét của @ Plantsrule14: Điều này không hoạt động vì máy tính không xử lý các số giống như các nhà toán học. Điểm nổi có vấn đề làm tròn, vì vậy bạn khó có thể có câu trả lời đúng. Ngay cả khi bạn sử dụng toán học số nguyên, MAX_INT + MAX_INT cho -2, do đó, tối đa (MAX_INT, MAX_INT) sử dụng công thức của bạn sẽ xuất hiện dưới dạng -1.
dùng9876

-3

Cách đơn giản nhất là định nghĩa nó là một hàm toàn cục trong một .htệp và gọi nó bất cứ khi nào bạn muốn, nếu chương trình của bạn là mô-đun với nhiều tệp. Nếu không, double MIN(a,b){return (a<b?a:b)}là cách đơn giản nhất.


1
@technosaurus Sẽ rất hữu ích nếu bạn mô tả lý do tại sao giải pháp này sai, không chỉ là như vậy.
Tur1ng

@technosaurus, phản ứng của bạn thực sự không có ích. Tur1ing, có vẻ như chức năng được xác định hoàn toàn sai (thiếu loại trên thông số đầu vào, thiếu dấu chấm phẩy sau câu lệnh return) và chuyển đổi đầu vào int thành gấp đôi là một cách kém để thực hiện, vì vậy loại không nên gấp đôi. Một biểu thức xác định hoặc câu lệnh sẽ tốt hơn ở đây (ví dụ: xem ở đây ), nhưng nếu một hàm, hãy xem xét tạo một hàm để làm điều này cho các kiểu int32_t, một cho các kiểu uint32_t và một cho các kiểu float hoặc double, tổng cộng là 3 chức năng khác nhau.
Gabriel Staples

1
@GabrielStaples Câu trả lời này nên được gắn cờ là không phải là câu trả lời - không có gì giúp được. Mặc dù nó có thể được sử dụng như một ví dụ về cách sai nhất trong khoảng không gian nhỏ nhất. Đề xuất các hàm toàn cục trong một tiêu đề (không phải là nội tuyến tĩnh?) Sẽ phá vỡ mã với hơn 2 đơn vị biên dịch, thậm chí không biên dịch, đặt tên một hàm như macro, ngụ ý ints như 1989, trả lại gấp đôi mà không có lý do đã nêu, ngụ ý các diễn viên sẽ gây ra cảnh báo tốt nhất ... và quan trọng nhất là NÓ KHÔNG TRẢ LỜI CÂU HỎI - không chung chung, không an toàn và chắc chắn không phải là cách tốt nhất
technosaurus

Mỗi một trong những vấn đề đó đáng bị chỉ trích thêm mà không thể được đề cập chi tiết.
Technosaurus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.