Programing

C는 "예측" 루프 구조를 가지고 있는가?

c10106 2022. 5. 14. 09:34
반응형

C는 "예측" 루프 구조를 가지고 있는가?

거의 모든 언어에는 루프나 비슷한 것이 있다.C가 하나 있니?예시 코드 좀 올려줄래?

C에는 포레치가 없지만, 매크로는 자주 다음과 같은 것을 모방하기 위해 사용된다.

#define for_each_item(item, list) \
    for(T * item = list->head; item != NULL; item = item->next)

그리고 다음과 같이 사용될 수 있다.

for_each_item(i, processes) {
    i->wakeup();
}

어레이에 대한 반복도 가능하다.

#define foreach(item, array) \
    for(int keep = 1, \
            count = 0,\
            size = sizeof (array) / sizeof *(array); \
        keep && count != size; \
        keep = !keep, count++) \
      for(item = (array) + count; keep; keep = !keep)

그리고 다음과 같이 사용될 수 있다.

int values[] = { 1, 2, 3 };
foreach(int *v, values) {
    printf("value: %d\n", *v);
}

편집: C++ 솔루션에 관심이 있는 경우, C++에는 "기준 범위"라는 기본 구문이 있음

아마 이미 알고 계실 테지만, C에는 "예측" 스타일의 루프가 없다.

비록 이 문제를 해결하기 위해 이미 엄청난 양의 매크로가 제공되어 있지만, 아마도 당신은 이 매크로가 유용하다는 것을 알게 될 것이다.

// "length" is the length of the array.   
#define each(item, array, length) \
(typeof(*(array)) *p = (array), (item) = *p; p < &((array)[length]); p++, (item) = *p)

...과 함께 사용할 수 있는 것for(의 경우와 같이)for each (...)).

이 접근 방식의 장점:

  • item(Python!에서처럼) for 문 안에서 선언되고 증분된다.
  • 모든 1차원 어레이에서 작동하는 것 같음
  • 매크로에서 생성된 모든 변수(p,item()는 (for 루프 헤더에 선언되었으므로) 루프 범위 밖에서는 보이지 않는다.

단점:

  • 다차원 배열에서는 작동하지 않음
  • 의존하다typeof(), 표준 C의 일부가 아닌 GNU 확장인 경우
  • for 루프 헤더에서 변수를 선언하므로 C11 이상에서만 작동한다.

시간을 절약하기 위해 테스트 방법을 알아보십시오.

typedef struct {
    double x;
    double y;
} Point;

int main(void) {
    double some_nums[] = {4.2, 4.32, -9.9, 7.0};
    for each (element, some_nums, 4)
        printf("element = %lf\n", element);

    int numbers[] = {4, 2, 99, -3, 54};
    // Just demonstrating it can be used like a normal for loop
    for each (number, numbers, 5) { 
        printf("number = %d\n", number);
        if (number % 2 == 0)
                printf("%d is even.\n", number);
    }

    char* dictionary[] = {"Hello", "World"};
    for each (word, dictionary, 2)
        printf("word = '%s'\n", word);

    Point points[] = {{3.4, 4.2}, {9.9, 6.7}, {-9.8, 7.0}};
    for each (point, points, 3)
        printf("point = (%lf, %lf)\n", point.x, point.y);

    /* Neither p, element, number or word are visible outside the scope of
    their respective for loops. Try to see if these printfs work (they shouldn't): */
    //printf("*p = %s", *p);
    //printf("word = %s", word);

    return 0;
}

기본적으로 gcc와 clang에 효과가 있는 것 같다; 다른 컴파일러는 테스트하지 않았다.

C는 각 구성물에 대해 a를 가지고 있지 않지만, 배열 끝의 한 부분에는 항상 관용적인 표현을 가지고 있다.(&arr)[1]. 이렇게 하면 다음과 같이 각 루프에 대해 간단한 관용어를 쓸 수 있다.

int arr[] = {1,2,3,4,5};
for(int *a = arr; a < (&arr)[1]; ++a)
    printf("%d\n", *a);

C에 갇혀 있을 때 쓰는 것은 이렇다.같은 범위 내에서 같은 아이템 이름을 두 번 사용할 수는 없지만, 우리 모두가 멋진 새로운 컴파일러를 사용할 수 있는 것은 아니기 때문에 그것은 문제가 되지 않는다. ()

#define FOREACH(type, item, array, size) \
    size_t X(keep), X(i); \
    type item; \
    for (X(keep) = 1, X(i) = 0 ; X(i) < (size); X(keep) = !X(keep), X(i)++) \
        for (item = (array)[X(i)]; X(keep); X(keep) = 0)

#define _foreach(item, array) FOREACH(__typeof__(array[0]), item, array, length(array))
#define foreach(item_in_array) _foreach(item_in_array)

#define in ,
#define length(array) (sizeof(array) / sizeof((array)[0]))
#define CAT(a, b) CAT_HELPER(a, b) /* Concatenate two symbols for macros! */
#define CAT_HELPER(a, b) a ## b
#define X(name) CAT(__##name, __LINE__) /* unique variable */

사용량:

int ints[] = {1, 2, 0, 3, 4};
foreach (i in ints) printf("%i", i);
/* can't use the same name in this scope anymore! */
foreach (x in ints) printf("%i", x);

편집: 다음에 대한 대안이 있다.FOREACH네임스페이스 오염을 방지하기 위해 c99 구문 사용:

#define FOREACH(type, item, array, size) \
    for (size_t X(keep) = 1, X(i) = 0; X(i) < (size); X(keep) = 1, X(i)++) \
    for (type item = (array)[X(i)]; X(keep); X(keep) = 0)

C에는 전조가 없다.

당신은 데이터를 반복하기 위해 for 루프를 사용할 수 있지만, 길이를 알아야 하거나 데이터를 know 값(예: null)으로 종료해야 한다.

char* nullTerm;
nullTerm = "Loop through my characters";

for(;nullTerm != NULL;nullTerm++)
{
    //nullTerm will now point to the next character.
}

다음은 C99의 매크로에 대한 전체 프로그램 예시:

#include <stdio.h>

typedef struct list_node list_node;
struct list_node {
    list_node *next;
    void *data;
};

#define FOR_EACH(item, list) \
    for (list_node *(item) = (list); (item); (item) = (item)->next)

int
main(int argc, char *argv[])
{
    list_node list[] = {
        { .next = &list[1], .data = "test 1" },
        { .next = &list[2], .data = "test 2" },
        { .next = NULL,     .data = "test 3" }
    };

    FOR_EACH(item, list)
        puts((char *) item->data);

    return 0;
}

기능 포인터로 작업할 계획인 경우

#define lambda(return_type, function_body)\
    ({ return_type __fn__ function_body __fn__; })

#define array_len(arr) (sizeof(arr)/sizeof(arr[0]))

#define foreachnf(type, item, arr, arr_length, func) {\
    void (*action)(type item) = func;\
    for (int i = 0; i<arr_length; i++) action(arr[i]);\
}

#define foreachf(type, item, arr, func)\
    foreachnf(type, item, arr, array_len(arr), func)

#define foreachn(type, item, arr, arr_length, body)\
    foreachnf(type, item, arr, arr_length, lambda(void, (type item) body))

#define foreach(type, item, arr, body)\
    foreachn(type, item, arr, array_len(arr), body)

사용량:

int ints[] = { 1, 2, 3, 4, 5 };
foreach(int, i, ints, {
    printf("%d\n", i);
});

char* strs[] = { "hi!", "hello!!", "hello world", "just", "testing" };
foreach(char*, s, strs, {
    printf("%s\n", s);
});

char** strsp = malloc(sizeof(char*)*2);
strsp[0] = "abcd";
strsp[1] = "efgh";
foreachn(char*, s, strsp, 2, {
    printf("%s\n", s);
});

void (*myfun)(int i) = somefunc;
foreachf(int, i, ints, myfun);

하지만 이것은 gcc에만 효과가 있을 것이라고 생각한다(확실하지 않다.

C는 다음의 구현을 가지고 있지 않다.for-each 분석할 때 때문에 알 수 배열을 점으로 구문 분석할 때 수신기는 배열이 얼마나 긴지 모르기 때문에 배열이 언제 끝나는지 알 수 없다.기억하라, C에서int*int를 포함하는 메모리 주소의 지점이다.순서에 따라 배치된 정수 수에 대한 정보를 포함하는 헤더 개체는 없다.그러므로 프로그래머는 이것을 추적할 필요가 있다.

그러나, 리스트의 경우, a와 유사한 것을 구현하는 것이 쉽다.for-each고리를 두르다

for(Node* node = head; node; node = node.next) {
   /* do your magic here */
}

어레이와 유사한 작업을 수행하려면 두 가지 작업 중 하나를 수행하십시오.

  1. 첫 번째 요소를 사용하여 배열 길이를 저장하십시오.
  2. 배열의 길이와 포인터를 고정하는 구조로 배열을 감싼다.

다음은 그러한 구조물의 예다.

typedef struct job_t {
   int count;
   int* arr;
} arr_t;

이것은 꽤 오래된 질문이지만, 나는 이것을 게시해야 한다.그것은 GNU C99를 위한 포러치 루프다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define FOREACH_COMP(INDEX, ARRAY, ARRAY_TYPE, SIZE) \
  __extension__ \
  ({ \
    bool ret = 0; \
    if (__builtin_types_compatible_p (const char*, ARRAY_TYPE)) \
      ret = INDEX < strlen ((const char*)ARRAY); \
    else \
      ret = INDEX < SIZE; \
    ret; \
  })

#define FOREACH_ELEM(INDEX, ARRAY, TYPE) \
  __extension__ \
  ({ \
    TYPE *tmp_array_ = ARRAY; \
    &tmp_array_[INDEX]; \
  })

#define FOREACH(VAR, ARRAY) \
for (void *array_ = (void*)(ARRAY); array_; array_ = 0) \
for (size_t i_ = 0; i_ && array_ && FOREACH_COMP (i_, array_, \
                                    __typeof__ (ARRAY), \
                                    sizeof (ARRAY) / sizeof ((ARRAY)[0])); \
                                    i_++) \
for (bool b_ = 1; b_; (b_) ? array_ = 0 : 0, b_ = 0) \
for (VAR = FOREACH_ELEM (i_, array_, __typeof__ ((ARRAY)[0])); b_; b_ = 0)

/* example's */
int
main (int argc, char **argv)
{
  int array[10];
  /* initialize the array */
  int i = 0;
  FOREACH (int *x, array)
    {
      *x = i;
      ++i;
    }

  char *str = "hello, world!";
  FOREACH (char *c, str)
    printf ("%c\n", *c);

  return EXIT_SUCCESS;
}

이 코드는 GNU/리눅스에서 gcc, icc, clang과 함께 작동하도록 테스트되었다.

여기 간단한 루프를 위한 싱글이 있다.

#define FOREACH(type, array, size) do { \
        type it = array[0]; \
        for(int i = 0; i < size; i++, it = array[i])
#define ENDFOR  } while(0);

int array[] = { 1, 2, 3, 4, 5 };

FOREACH(int, array, 5)
{
    printf("element: %d. index: %d\n", it, i);
}
ENDFOR

원하는 경우 인덱스에 대한 액세스 권한 제공(i 현재 및 현재 인 인데 ()it루프를 중첩할 때 이름 지정 문제가 발생할 수 있으므로 항목과 인덱스 이름을 매크로의 매개 변수가 될 수 있다.

의 수정된 승인 인의 수식어 버전.foreach. 를 지정할 수 있음start인덱스, 더size분해된 어레이(점퍼)에서 작동할 수 있도록,int*그리고 바뀌었다.count != sizei < size사용자가 실수로 'i'를 보다 크게 수정하는 경우size무한 루프에 갇히게 될 거야

#define FOREACH(item, array, start, size)\
    for(int i = start, keep = 1;\
        keep && i < size;\
        keep = !keep, i++)\
    for (item = array[i]; keep; keep = !keep)

int array[] = { 1, 2, 3, 4, 5 };
FOREACH(int x, array, 2, 5)
    printf("index: %d. element: %d\n", i, x);

출력:

index: 2. element: 3
index: 3. element: 4
index: 4. element: 5

C에는 'for'와 'while' 키워드가 있다.만약 C#과 같은 언어로 된 포레치 문장이 이렇게 생긴다면...

foreach (Element element in collection)
{
}

... 그렇다면 C의 이 포레치 문장에 해당하는 것은 다음과 같을 수 있다.

for (
    Element* element = GetFirstElement(&collection);
    element != 0;
    element = GetNextElement(&collection, element)
    )
{
    //TODO: do something with this element instance ...
}

에릭의 대답은 "break" 또는 "계속"을 사용할 때 작동하지 않는다.

이 문제는 첫 번째 줄을 다시 써서 해결할 수 있다.

원래 라인(재조정됨):

for (unsigned i = 0, __a = 1; i < B.size(); i++, __a = 1)

고정:

for (unsigned i = 0, __a = 1; __a && i < B.size(); i++, __a = 1)

요하네스의 루프와 비교해 보면, 그가 실제로 같은 행동을 하고 있다는 것을 알 수 있을 것이다. 단지 조금 더 복잡하고 추한 행동일 뿐이다.

참조URL: https://stackoverflow.com/questions/400951/does-c-have-a-foreach-loop-construct

반응형