문제

내가 만들려고 의사 슈퍼 구조체를 인쇄 편의 구조체.내 basic 구조는 다음과 같습니다.

/* Type 10 Count */
typedef struct _T10CNT
{
    int _cnt[20];
} T10CNT;

...

/* Type 20 Count */
typedef struct _T20CNT
{
    long _cnt[20];
} T20CNT;
...

내가 만든 아래 구조체를 인쇄의 배열 위에 언급된 구조물입니다.내가 참조 void 포인터를 오류를 컴파일하는 동안 아래 코드.

typedef struct _CMNCNT
{
    long  _cnt[3];
} CMNCNT;

static int printCommonStatistics(void *cmncntin, int cmncnt_nelem, int cmncnt_elmsize)
{
    int ii;
    for(ii=0; ii<cmncnt_nelem; ii++)
    {
        CMNCNT *cmncnt = (CMNCNT *)&cmncntin[ii*cmncnt_elmsize];
        fprintf(stout,"STATISTICS_INP: %d\n",cmncnt->_cnt[0]);
        fprintf(stout,"STATISTICS_OUT: %d\n",cmncnt->_cnt[1]); 
        fprintf(stout,"STATISTICS_ERR: %d\n",cmncnt->_cnt[2]);
    }
    return SUCCESS;
}

T10CNT struct_array[10];
...
printCommonStatistics(struct_array, NELEM(struct_array), sizeof(struct_array[0]);
...

내 의도가 일반적인 기능을 인쇄하는 모든 배열입니다.알려주시기 바랍에 올바른 방법으로 사용하는니다.

도움을 주셔서 감사합니다.

편집:매개 변수 이름은 변경 cmncntin 에서 cmncnt.죄 그것은 오타 오류가 있습니다.

감사합니다, 예를 은 매튜

도움이 되었습니까?

해결책

나는 당신의 디자인을 실패하지만 나도 모호하는 다른 답변을 나는 완전히 다루는 깊은 이유는 이렇습니다.

그것은 당신을 사용하려 C 을 다루는 일반적인 유형,뭔가가 항상을 털.당신이 그것을 할 수 있습니다,당신은 조심해야 하지만,그것은 쉬운 일이 아닙니다,이 경우에는,나면 의심 될 것이 가치가 있습니다.

깊은 이유:다고 가정해 봅시다 과거에는 단순한 구문(또는 거 이상 구문)문제입니다.귀하의 코드를 보여주는 T10CNT 담 20 int 고 T20CNT 담 20 long.에 현대적이 64 비트 컴퓨터-아닌 다른 Win64- sizeof(long) != sizeof(int).따라서,코드는 안쪽에 인쇄 기능이 있어야 사이를 구별 참조 int 배열 및 long 배열입니다.에서는 C++,가해야 하는지를 치료하려고 다형적으로 배열하고,이런 종류의 것입니다.이 CMNCNT 유형을 포함 3 long 가다른 모두에서 T10CNT 및 T20CNT 구조물에서 수만,기본 형식의 배열과 일치하 T20CNT.

스타일이 추천:나는 강하게 피하는 것이 좋습니다 선행 밑줄에 이름이 있습니다.일반적으로 이름이 시작 밑줄 예약 구현을 위해 사용으로 사용하는 매크로입니다.매크로에 대한 존중이 없는 범위;는 경우 구현을 정의 매크로 _cnt 그것은 난파선의 코드입니다.뉘앙스가있을 것 이름은 예약되어 있습니다;지에 대한 이동으로 그 뉘앙스가 있습니다.그것은 훨씬 간단하게 생각하는'이름이 시작과 함께 밑줄 예약되어 있',그리고 그것은 당신을 조종의 명확한 문제입니다.

스타일 제안:인쇄 기능은 반환한 성공은 무조건적으로.는 분별하지 않습니다;귀하의 기능을 반환해야 합니다,아무것도록 호출이 없을 테스트하는 성공을 위해 또는 오류(수 있기 때문에 그것은 결코 실패하지 않).주의 coder 들을 관찰하는 반환 상태를 항상 테스트를 반환 상태,그리고 오류 처리 코드입니다.는 코드는 실행되지 않을 것이다,그래서 그것은 죽었지만,그것은 사람을 위해 열심히(또는 컴파일러)을 결정한다.

표면 수정:일시적으로,우리는 할 수 있다고 가정할 수 있는 치료 intlong 동의어로;하지만 당신은 나의 습관이 있다는 생각에 동의어,하지만.이 void * 인자가 올바른 방법으로"말하는 이 함수 포인터의 불확실 유형".그러나,기능,내부를 변환해야에서 void * 을 특정 유형은 당신이 전에 indexing.

typedef struct _CMNCNT
{
    long    count[3];
} CMNCNT;

static void printCommonStatistics(const void *data, size_t nelem, size_t elemsize)
{
    int i;
    for (i = 0; i < nelem; i++)
    {
        const CMNCNT *cmncnt = (const CMNCNT *)((const char *)data + (i * elemsize));
        fprintf(stdout,"STATISTICS_INP: %ld\n", cmncnt->count[0]);
        fprintf(stdout,"STATISTICS_OUT: %ld\n", cmncnt->count[1]); 
        fprintf(stdout,"STATISTICS_ERR: %ld\n", cmncnt->count[2]);
    }
}

(좋아한 아이디어 파일의 스트림라 stout 너무입니다. 제안:사용 컷'n 하여 붙여넣기에 실제 소스 코드-그것은 안전합니다!나는 일반적으로 사용하"sed 's/^/ /' file.c"를 준비하는 코드를 절단'n 하여 붙여넣기로 이렇게 대답합니다.)

무엇을 캐스팅 라인가?나는 당신이 기뻐했습니다.

  • 첫 번째 작업을 변환할 const void *const char *;것을 할 수 있습니다 바이트로 크기의 작업에서 주소입니다.에서 일하기 전에는 표준 C char * 에서 사용 되었소 void * 으로 보편적인 해결 메커니즘이 있습니다.
  • 다음 동작을 추가 올바른 바이트 수를 얻을 시작 ith 배열의 요소의 개체의 크기 elemsize.
  • 두 번째 던지기에 의하면 컴파일러는"신뢰-나는 내가 무슨 일을"그리고"이것을 대우하는 주소로의 주소 CMNCNT 구조".

거기에서,코드는 쉽게 충분합니다.참고로부터 구조에 포함 CMNCNT long 가치,내가 사용하는 %ld 진실을 말하 fprintf().

지 않기 때문에 당신은 당해 데이터를 수정에서 이 기능,그것은 나쁜 생각하는 사용 const 규정으로 했습니다.

참고는 당신이 가고 있는 충실하라 sizeof(long) != sizeof(int), 에,당신은 필요 두 별도의 블록의 코드(나는 별도의 기능)를 다루는'배열의 int'그리고'배열의 long'구조 형식입니다.

다른 팁

빈 공간의 유형은 고의적으로 불완전하게 남아 있습니다. 이것으로부터, 그것은 당신이 void pointers를 불러 일으킬 수 없으며, 당신은 그것의 크기를 취할 수 없습니다. 즉, 배열처럼 사용하여 첨자 연산자를 사용할 수 없습니다.

공허 포인터에 무언가를 할당하는 순간, 원래 유형의 유형 정보가 손실되므로 원래 포인터 유형으로 처음으로 시전하면 단위로 만 회의를 할 수 있습니다.

먼저 가장 중요한 것은지나갑니다 T10CNT* 함수에, 그러나 당신은 CMNCNT* 당신의 기능에서. 이것은 유효하고 정의되지 않은 동작이 아닙니다.

각 유형의 배열 요소에 대한 함수 printCommonStatistics가 필요합니다. 그래서,printCommonStatisticsInt, printCommonStatisticsLong, printCommonStatisticsChar 모든 것이 그들의 첫 번째 주장에 의해 다른 int*, 다른 사람은 long*, 등등). 중복 코드를 피하기 위해 매크로를 사용하여 만들 수 있습니다.

구조물 자체를 통과하는 것은 좋은 생각이 아니므로 구조물 내에서 포함 된 배열의 각기 다른 크기에 대해 새 함수를 정의해야합니다 (모두 다른 유형이므로). 따라서 포함 된 배열을 직접 통과하는 것이 좋습니다 (struct_array[0]._cnt, 각 색인의 기능을 호출하십시오)

함수 선언을 char *처럼 변경하십시오.

static int printCommonStatistics(char *cmncnt, int cmncnt_nelem, int cmncnt_elmsize)

공극 유형은 특정 크기를 가정하지 않지만 숯은 바이트 크기를 가정합니다.

당신은 이것을 할 수 없습니다 :

cmncnt->_cnt[0]

CMNCT가 무효 포인터 인 경우.

유형을 지정해야합니다. 구현을 다시 생각해야 할 수도 있습니다.

함수

static int printCommonStatistics(void *cmncntin, int cmncnt_nelem, int cmncnt_elmsize)
{
    char *cmncntinBytes;
    int ii;

    cmncntinBytes = (char *) cmncntin;
    for(ii=0; ii<cmncnt_nelem; ii++)
    {
        CMNCNT *cmncnt = (CMNCNT *)(cmncntinBytes + ii*cmncnt_elmsize);  /* Ptr Line */
        fprintf(stdout,"STATISTICS_INP: %d\n",cmncnt->_cnt[0]);
        fprintf(stdout,"STATISTICS_OUT: %d\n",cmncnt->_cnt[1]); 
        fprintf(stdout,"STATISTICS_ERR: %d\n",cmncnt->_cnt[2]);
    }
    return SUCCESS;
}

나를 위해 일합니다.

문제는 라인에서 "PTR Line"에 주석을 달린다는 것입니다. 코드는 정수에 포인터를 추가한다는 것입니다. 우리의 포인터는 char *이기 때문에 우리는 (char) * ii * cmncnt_elemsize의 메모리 크기로 앞으로 나아갑니다. char가 하나의 바이트이기 때문에 우리가 원하는 것입니다. 코드는 (void) * ii * cmncnt_elemsize의 앞으로 나가는 동등한 일을 시도했지만 void에는 크기가 없으므로 컴파일러에 오류가 발생했습니다.

나는 t10cnt와 t20cnt를 변경하여 각각 하나 대신 int 또는 long을 사용하도록 변경합니다. 당신은 sizeof (int) == sizeof (long)에 따라 다릅니다.

이 라인에서 :

CMNCNT *cmncnt = (CMNCNT *)&cmncnt[ii*cmncnt_elmsize];

CMNCNT라는 새로운 변수를 선언하려고하지만이 이름을 가진 변수는 이미 함수의 매개 변수로 존재합니다. 다른 변수 이름을 사용하여이를 해결할 수 있습니다.

또한 CMNCNT에 대한 포인터를 공간 포인터 대신 함수로 전달할 수 있습니다. 컴파일러는 귀하를 위해 포인터 산술을 수행하고 캐스트 할 필요가 없기 때문입니다. 나는 당신이 그것으로하는 모든 일이 cmncnt에 캐스팅 될 때 빈 공간 포인터를 통과하는 지점을 보지 못합니다. (데이터 유형에 대한 설명적인 이름이 아닙니다.)

당신의 표현

(CMNCNT *)&cmncntin[ii*cmncnt_elmsize]

cmncntin [ii *cmncnt_elmsize]의 주소를 취한 다음 그 포인터를 타입 (cmncnt *)에 캐스트하려고합니다. cmncntin의 유형 void*가 있기 때문에 cmncntin [ii*cmncnt_elmsize]의 주소를 얻을 수 없습니다.

C의 연산자 우선 순위를 연구하고 필요한 경우 괄호 안에 삽입하십시오.

의 포인트 정보:내부 패딩 수 있습니다 정말 나사 이다.

고려 struct{char c[6];};-그것은 sizeof()=6.하지만 경우에 당신의 배열을,이러한 각각의 요소가 될 수 있 패딩 아웃 8 바이트의 정렬!

특정 어셈블리 작업을 처리하지 않 mis 맞추는 데이터가 정상적입니다.(예를 들면,int 에 걸쳐 두 가지 메모리 단어입니다.) (예,내가에게 물린 적이 있습니다.)

.

두 번째:과거에는,내가 사용한 가변 크기의 배열입니다.(나는 바보 돌아 그...)그것은 작동하지 않은 경우 변경하는 유형입니다.(있을 경우 또는 연합의 유형입니다.)

E.g.:

struct T { int sizeOfArray;  int data[1]; };

으로 할당

T * t = (T *) malloc( sizeof(T) + sizeof(int)*(NUMBER-1) );
                      t->sizeOfArray = NUMBER;

(지만 패딩/조율은 여전히 나사를 합니다.)

.

셋째생각해 보십시오:

   struct T {
     int sizeOfArray;
     enum FOO arrayType;
     union U { short s; int i; long l; float f; double d; } data [1];
    };

그것이 문제를 해결을 인쇄하는 방법으로 데이터입니다.

.

넷째할 수 있습니다 그냥 전달 int/길이 배열의 기능이 아닌 구조입니다.E.g:

void printCommonStatistics( int * data, int count )
{
  for( int i=0;  i<count;  i++ )
    cout << "FOO: " << data[i] << endl;
}

를 통해 호출되:

_T10CNT  foo;
printCommonStatistics( foo._cnt, 20 );

또:

 int a[10], b[20], c[30];
printCommonStatistics( a, 10 );
printCommonStatistics( b, 20 );
printCommonStatistics( c, 30 );

이 작품보다 훨씬 더 숨어있는 데이터는 구조체.으로 멤버를 추가 하나의 구조체의 레이아웃을 변경할 수 있습 사이의 구조체와 더 이상 일치한다.(을 의미의 주소 _cnt 해 상대적으로 구조체의 변경될 수 있습에 대한 _T10CNT 및 _T20CNT.재미있는 디버깅 있다.하나의 구조체로 union'ed_cnt 페이로드를 피할 것이다.)

E.g.:

struct FOO {
  union {
         int     bar  [10];
          long biff [20];
   } u;
}

.

다섯 번째:해야 하는 경우에는 사용하는 구조체를...C++,iostreams 며,템플릿은 많은 것입 청소기를 구현할 수 있습니다.

E.g.:

template<class TYPE> void printCommonStatistics( TYPE & mystruct, int count )
{
  for( int i=0;  i<count;  i++ )
    cout << "FOO: " << mystruct._cnt[i] << endl;
}      /* Assumes all mystruct's have a "_cnt" member. */

지만 아마 당신이 찾고있는 무엇을 위해...

C는 내 컵 O'Java가 아니지만 "void *cmncnt"는 cmncnt *cmncnt 여야한다고 생각합니다.

C 프로그래머들에게 지금 나를 바로 잡으십시오. 이것이 Java 프로그래머가 좋은 것을 가질 수없는 이유입니다.

이 라인은 고문 당했다고 생각하지 않습니까?

CMNCNT *cmncnt = (CMNCNT *)&cmncntin[ii*cmncnt_elmsize];

더 좋아하는 것은 어떻습니까?

CMNCNT *cmncnt = ((CMNCNT *)(cmncntin + (ii * cmncnt_elmsize));

또는 더 나은 아직, cmncnt_elmsize = sizeof (cmncnt)

CMNCNT *cmncnt = ((CMNCNT *)cmncntin) + ii;

더 이상 공허 *를 해석하지 않기 때문에 경고를 제거해야합니다.

BTW : 왜 당신이 왜 이런 식으로하고 있는지 잘 모르겠지만, cmncnt_elmsize가 때때로 크기가 아니고 (cmncnt), 실제로 통화마다 다를 수 있다면,이 디자인을 다시 생각하는 것이 좋습니다. 나는 그것에 대한 좋은 이유가있을 수 있다고 생각하지만, 그것은 나에게 정말로 흔들리는 것처럼 보입니다. 나는 물건을 디자인하는 더 좋은 방법이 있음을 거의 보장 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top