min() / max() problems in C++

항상 C++로 코딩을 하면서 min()이나 max() 함수(최소값/최대값을 리턴하는 함수)를 쓸때 이상한 에러를 맞닥뜨리곤 한다.

나중에 안 사실이지만 이 것은 min()/max() 라는 이름으로 선언된 함수들끼리 서로 충돌을 일으키기 때문이다. 즉 include 한 header 파일 내에 동일한 이름으로 다른 함수들이 선언되어 있는 것이다.

몇가지 해결책을 이 블로그에서 찾았다. 해결책은 아래와 같다.


I always confronted something weird errors when I use min() or max() function in C++.

Actually, it because of conflicts between the functions with same name.

I found several solutions for this problems from this blog post.

And solutions suggested are following. (prioritized with best approach first):


이하 내용은 블로그에서 인용.

Following suggestions are cited from the blog.

  • Convert your source code to use the Standard C++ std::min() and std::max() and ensure that you #include . Use
#include <algorithm> 
using namespace std;

// use min() instead of std::min()
// use max() instead of std::max()
  • Define the NOMINMAX macro to instruct WinDef.h not to define the min/max macros. E.g. you can update your Visual C++ compiler options with /D NOMINMAX or you can insert #define NOMINMAX.

  • Redefine min/max in the specific problematic files. Especially this may be needed in you include gdiplus Windows headers files, because these uses the Windows min/max macros.

#include <algorithm> 

#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif

#include <gdiplus.h>
#undef max
#undef min

using namespace std;
  • Alternatively redefine min/max to use use the Visual C++ non-standard __min()/__max(). But min/max are still defined as macros and will likely lead to problems. Not a good solution.
#ifndef max
#define max __max
#endif
#ifndef min
#define min __min
#endif
  • Alternatively use Visual C++ compiler options /Dmin=__min / Dmax=__max. This will tell compiler and WinDef.h not to define min/max macros and use __min() and __max() functions instead as defined in (or ) so ensure this is included. But min/max are still defined as macros and will likely lead to problems. Not a good solution.

Thanks to Michael Suodenjoki !

C / C++ – Fast add nanoseconds to timespec structure

C나 C++ 프로그램에서 나노세컨트 단위의 시간을 처리해야 하는 경우가 간혹 있는데 이 경우에는 timespec 구조체를 사용하는 것이 적당하다.

만약 timespec을 사용하다가 특정 시점에서 몇 나노 세컨드 이후의 timespec이 필요한 경우에는 아래의 Snippet을 활용하면 된다. 워낙 짧은 시간이다 보니 시간을 더하는 연산의 속도가 매우 중요하다.

코드는 GitHub Gist – BinaryPrison 에서 참조하였다.


Sometimes you may need to handle nanoseconds in C or C++. In this case, using timespec structure is appropriate approach.

And if you need to add some nanoseconds to your timespec, this snippet below would be helpful.

The snippet is from GitHub Gist – BinaryPrison


static inline uint32_t __iter_div_u64_rem(uint64_t dividend, uint32_t divisor, uint64_t *remainder)
{
  uint32_t ret = 0;

  while (dividend >= divisor) {
    /* The following asm() prevents the compiler from
       optimising this loop into a modulo operation.  */
    asm("" : "+rm"(dividend));

    dividend -= divisor;
    ret++;
  }

  *remainder = dividend;

  return ret;
}

#define NSEC_PER_SEC  1000000000L
static inline void timespec_add_ns(struct timespec *a, uint64_t ns)
{
  a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns);
  a->tv_nsec = ns;
}

C / C++ – kbhit() function in Linux

Linux에서는 Windows C / C++ 라이브러리에서 제공되는 kbhit() 함수 (keyboard event를 detect 하는 함수 : keystroke가 들어왔을때 이를 감지함)를 사용할 수 없다.

대신 아래의 오픈소스 snippet을 이용하여, kbhit() 함수를 직접 구현하면 된다. 코드의 출처는 Indra17 블로그 이다.


kbhit() function detecting keyboard hitting event, is provided by Windows C / C++ library. But it is not available in Linux.

Thus, you should implement your kbhit() function in your own.
The code below is open source snippet for kbhit(). Please refer to Indra17 blog (in Korean) for more information.


// There's no kbhit() function in linux if you want to use kbhit() function, use this code as below.
// reference : http://indra17.tistory.com/60

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <termios.h>

static struct termios initial_settings, new_settings;

static int peek_character = -1;

void init_keyboard()
{
    tcgetattr(0,&initial_settings);
    new_settings = initial_settings;
    new_settings.c_lflag &= ~ICANON;
    new_settings.c_lflag &= ~ECHO;
    new_settings.c_cc[VMIN] = 1;
    new_settings.c_cc[VTIME] = 0;
    tcsetattr(0, TCSANOW, &new_settings);
}

void close_keyboard()
{
    tcsetattr(0, TCSANOW, &initial_settings);
}

int _kbhit()
{
    unsigned char ch;
    int nread;

    if (peek_character != -1) return 1;
    new_settings.c_cc[VMIN]=0;
    tcsetattr(0, TCSANOW, &new_settings);
    nread = read(0,&ch,1);
    new_settings.c_cc[VMIN]=1;
    tcsetattr(0, TCSANOW, &new_settings);
    if(nread == 1)
    {
        peek_character = ch;
        return 1;
    }
    return 0;
}

int _getch()
{
    char ch;

    if(peek_character != -1)
    {
        ch = peek_character;
        peek_character = -1;
        return ch;
    }
    read(0,&ch,1);
    return ch;
}

int _putch(int c) {
    putchar(c);
    fflush(stdout);
    return c;
}

// use above functions in this way
int main()
{
    init_keyboard();

    while (1) {
        if (_kbhit()) {
            int ch = _getch();
            _putch(ch);
            switch (ch) {
                ...
            }
        }
    }
    close_keyboard();

    return 0;
}