source

일반 스왑 매크로를 C에 구현

manycodes 2023. 10. 3. 11:05
반응형

일반 스왑 매크로를 C에 구현

중복 가능:
c에 std:: swap()와 동등한 값이 있습니까?

안녕하세요 여러분.

일반 스왑 매크로를 C에 작성하는 데 문제가 발생했는데 매크로는 다음과 같습니다.

#define swap(x,y) { x = x + y; y = x - y; x = x - y; }

정수와 플로트는 잘 작동하지만 문제점이 있는지 잘 모르겠습니다.일반 매크로가 포인터, 문자 등을 교환하는 것을 의미한다면 어떨까요? 모든 입력을 교환하기 위한 일반 매크로를 작성하는 데 도움을 줄 수 있는 사람이 있습니까?

감사해요.

이것은 정수에서만 잘 작동합니다.

플로트의 경우 실패합니다(예: 매우 큰 플로트와 매우 작은 플로트를 사용하여 플로트를 실행해 보십시오).

저는 다음과 같이 제안하고 싶습니다.

#define swap(x,y) do \ 
   { unsigned char swap_temp[sizeof(x) == sizeof(y) ? (signed)sizeof(x) : -1]; \
     memcpy(swap_temp,&y,sizeof(x)); \
     memcpy(&y,&x,       sizeof(x)); \
     memcpy(&x,swap_temp,sizeof(x)); \
    } while(0)

memcpy는 compilation time에 복사할 양을 알 때 상당히 최적화됩니다.또한 수동으로 형식 이름을 전달하거나 컴파일러 고유 확장자를 사용할 필요가 없습니다.

다음과 같은 작업을 수행할 수 있습니다.

#define SWAP(x, y, T) do { T SWAP = x; x = y; y = SWAP; } while (0)

다음과 같이 호출할 수 있습니다.

SWAP(a, b, int);

또는:

SWAP(x, y, float);

gcc별 확장자를 사용할 수 있다면 다음과 같이 개선할 수 있습니다.

#define SWAP(x, y) do { typeof(x) SWAP = x; x = y; y = SWAP; } while (0)

그러면 다음과 같습니다.

SWAP(a, b);

또는:

SWAP(x, y);

포인터를 포함한 대부분의 유형에서 사용할 수 있습니다.

테스트 프로그램은 다음과 같습니다.

#include <stdio.h>

#define SWAP(x, y) do { typeof(x) SWAP = x; x = y; y = SWAP; } while (0)

int main(void)
{
    int a = 1, b = 2;
    float x = 1.0f, y = 2.0f;
    int *pa = &a;
    int *pb = &b;

    printf("BEFORE:\n");
    printf("a = %d, b = %d\n", a, b);
    printf("x = %f, y = %f\n", x, y);
    printf("pa = %p, pb = %p\n", pa, pb);

    SWAP(a, b);     // swap ints
    SWAP(x, y);     // swap floats
    SWAP(pa, pb);   // swap pointers

    printf("AFTER:\n");
    printf("a = %d, b = %d\n", a, b);
    printf("x = %f, y = %f\n", x, y);
    printf("pa = %p, pb = %p\n", pa, pb);

    return 0;
}

지맨은 이 시도를 시작했는데, 이것을 조합해서 코드화하는 것입니다.inline함수와 매크로.이 솔루션은 복합 리터럴을 사용하므로 C99를 지원하는 최신 C 컴파일러가 있다고 가정합니다.

inline void swap_detail(void* p1, void* p2, void* tmp, size_t pSize)
{
   memcpy(tmp, p1, pSize);
   memcpy(p1, p2, pSize);
   memcpy(p2 , tmp, pSize);
}
#define SWAP(a, b) swap_detail(&(a), &(b), (char[(sizeof(a) == sizeof(b)) ? (ptrdiff_t)sizeof(a) : -1]){0}, sizeof(a))

이 속성은 다음과 같습니다.

  • 각각을 평가합니다.a그리고.b단 한 번
  • 정확한 사이즈에 대한 컴파일 타임 체크가 있습니다.
  • 숨겨진 변수에 대한 이름 지정 문제가 없습니다.
  • 임시 변수의 크기는 컴파일 시간에 계산되므로 복합 리터럴은 동적 배열이 아닙니다.

출연진들(ptrdiff_t)필요한 것은 다음과 같습니다.-1에 자동으로 승격되지 않습니다.SIZE_MAX.

이 솔루션은 여전히 두 가지 단점을 안고 있습니다.

  1. 이것은 안전한 타입이 아닙니다.이는 유형의 크기만 확인하고 의미론은 확인하지 않습니다.종류가 다르면 a라고 합니다.double8사이즈와 a의uint64_t, 당신은 곤경에 처해있습니다.

  2. 표현식은 다음을 허용해야 합니다.&적용 가능한 연산자.따라서 다음과 같이 선언된 변수에서는 작동하지 않습니다.register스토리지 클래스.

간단히 말해서, 당신은 적어도 약간의 위험이나 두통 없이는 C에서 일반적스왑 매크로를 만들 수 없습니다.(기타 게시글 참조).설명은 아래와 같습니다.)

매크로는 좋지만 실제 코드에서 발생하는 문제는 데이터 유형 문제입니다(말씀하신 대로 말이죠.게다가 매크로는 어떤 면에서는 "멍청하다"고 할 수 있습니다.예를 들어,

를 들어 를 사용합니다.#define swap(x,y) { x = x + y; y = x - y; x = x - y; },swap(++x, y){ ++x = ++x + y; y = ++x - y; ++x = ++x - y;}.

.int x = 0, y = 0; swap(++x, y);당신은 얻을 것입니다.x=2, y=3x=0, y=0할 수 여기에 매크로의 온도 변수가 코드에 나타나면 성가신 오류가 발생할 수 있습니다.

고객님이 찾으시는 기능은 C++에 템플릿으로 도입되었습니다.C에서 가장 가까이 접근할 수 있는 것은 상상할 수 있는 각 데이터 유형에 대한 인라인 함수 또는 적절하게 복잡한 매크로를 사용하는 것입니다(이전 매크로 문제 및 이전 게시물 참조).

C++에서 템플릿을 사용하는 솔루션은 다음과 같습니다.

template<typename T>
inline void swap(T &x, T &y)
{
    T tmp = x;
    x = y; y = tmp;
}

C에서는 다음과 같은 것이 필요합니다.

inline void swap_int(int *x, int *y) { /* Code */ }
inline void swap_char(char *x, char *y) { /* Code */ }
// etc.

또는 (몇 번 언급한 바와 같이) 위험할 가능성이 있는 상당히 복잡한 매크로입니다.

에 가 있는 것은 .int규격에 따라서이 경우를 상상해 보세요.x그리고.y이었다INT_MAX그리고.INT_MAX-1각각 다음과 같다.첫 번째 addition 문은 표준에 의해 정의되지 않은 서명된 오버플로를 발생시킵니다.

에 대한 int 가 될 입니다.OR 스왑 알고리즘이 될 것입니다.

정말로, 코드에서 얼마나 많은 교환을 해야만 주어진 해결책을 가지고 이 스레드에서 발생하는 모든 골칫거리를 해결할 가치가 있습니까?제 말은, 이것은 복잡하고 오류가 발생하기 쉬운 코드 구조가 아니라, 한 개의 임시 변수와 세 개의 간단한 과제가 있는 잘 알려진 관용구입니다.공간을 절약하고 싶다면 한 줄이라도 필요한 곳에 쓰십시오.

function foo ()
{
    int a, b, tmp;
    ...
    tmp = a; a = b; b = tmp;
    ....
}

또는 a와 b가 더 복잡한 "로컬" 매크로를 사용합니다.

#define SWAP(t,a,b) ( (t) = (a), (a) = (b), (b) = (t) )

function foo (pointer)
{
    int tmp;
    ...
    SWAP(tmp, pointer->structure.array[count+1], pointer->structure.array[count+2]);
    ...
}

#undef SWAP

언급URL : https://stackoverflow.com/questions/3982348/implement-generic-swap-macro-in-c

반응형