사람들이 C / C ++에서하는 부당한 가정을 보여주는 교육 도구에는 무엇이 포함됩니까?


121

저는 초보자 (및 중급) 프로그래머가 C, C ++ 및 플랫폼에서 정당하지 않은 가정을 인식하고 이의를 제기하는 데 도움이되는 SO를위한 작은 교육 도구를 준비하고 싶습니다.

예 :

  • "정수를 둘러싼 다"
  • "모든 사람이 ASCII를 가지고 있습니다."
  • "함수 포인터를 void *에 저장할 수 있습니다."

저는 소규모 테스트 프로그램이 다양한 플랫폼에서 실행될 수 있다고 생각했습니다.이 가정은 일반적으로 경험이 부족한 / 반 경험이없는 많은 주류 개발자가 만든 "그럴듯한"가정을 실행하고 다양한 시스템에서 중단되는 방식을 기록합니다.

이것의 목표는 무언가를하는 것이 "안전"하다는 것을 증명하는 것이 아니라 (불가능할 것이고, 테스트가 깨질 경우에만 어떤 것을 증명 함), 대신 가장 눈에 띄지 않는 표현을 가장 이해하기 어려운 개인에게 보여주기위한 것입니다. 정의되지 않았거나 구현 정의 된 동작이있는 경우 다른 시스템에서 중단됩니다. .

이를 달성하기 위해 다음과 같이 질문하고 싶습니다.

  • 이 아이디어를 어떻게 개선 할 수 있습니까?
  • 어떤 테스트가 좋으며 어떻게 표시되어야합니까?
  • 손을 잡고 결과를 게시 할 수있는 플랫폼에서 테스트를 실행하여 결과를 게시하여 플랫폼 데이터베이스로 끝낼 수 있으며, 서로 어떻게 다른지, 왜이 차이가 허용되는지?

테스트 장난감의 현재 버전은 다음과 같습니다.

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <stddef.h>
int count=0;
int total=0;
void expect(const char *info, const char *expr)
{
    printf("..%s\n   but '%s' is false.\n",info,expr);
    fflush(stdout);
    count++;
}
#define EXPECT(INFO,EXPR) if (total++,!(EXPR)) expect(INFO,#EXPR)

/* stack check..How can I do this better? */
ptrdiff_t check_grow(int k, int *p)
{
    if (p==0) p=&k;
    if (k==0) return &k-p;
    else return check_grow(k-1,p);
}
#define BITS_PER_INT (sizeof(int)*CHAR_BIT)

int bits_per_int=BITS_PER_INT;
int int_max=INT_MAX;
int int_min=INT_MIN;

/* for 21 - left to right */
int ltr_result=0;
unsigned ltr_fun(int k)
{
    ltr_result=ltr_result*10+k;
    return 1;
}

int main()
{
    printf("We like to think that:\n");
    /* characters */
    EXPECT("00 we have ASCII",('A'==65));
    EXPECT("01 A-Z is in a block",('Z'-'A')+1==26);
    EXPECT("02 big letters come before small letters",('A'<'a'));
    EXPECT("03 a char is 8 bits",CHAR_BIT==8);
    EXPECT("04 a char is signed",CHAR_MIN==SCHAR_MIN);

    /* integers */
    EXPECT("05 int has the size of pointers",sizeof(int)==sizeof(void*));
    /* not true for Windows-64 */
    EXPECT("05a long has at least the size of pointers",sizeof(long)>=sizeof(void*));

    EXPECT("06 integers are 2-complement and wrap around",(int_max+1)==(int_min));
    EXPECT("07 integers are 2-complement and *always* wrap around",(INT_MAX+1)==(INT_MIN));
    EXPECT("08 overshifting is okay",(1<<bits_per_int)==0);
    EXPECT("09 overshifting is *always* okay",(1<<BITS_PER_INT)==0);
    {
        int t;
        EXPECT("09a minus shifts backwards",(t=-1,(15<<t)==7));
    }
    /* pointers */
    /* Suggested by jalf */
    EXPECT("10 void* can store function pointers",sizeof(void*)>=sizeof(void(*)()));
    /* execution */
    EXPECT("11 Detecting how the stack grows is easy",check_grow(5,0)!=0);
    EXPECT("12 the stack grows downwards",check_grow(5,0)<0);

    {
        int t;
        /* suggested by jk */
        EXPECT("13 The smallest bits always come first",(t=0x1234,0x34==*(char*)&t));
    }
    {
        /* Suggested by S.Lott */
        int a[2]={0,0};
        int i=0;
        EXPECT("14 i++ is strictly left to right",(i=0,a[i++]=i,a[0]==1));
    }
    {
        struct {
            char c;
            int i;
        } char_int;
        EXPECT("15 structs are packed",sizeof(char_int)==(sizeof(char)+sizeof(int)));
    }
    {
        EXPECT("16 malloc()=NULL means out of memory",(malloc(0)!=NULL));
    }

    /* suggested by David Thornley */
    EXPECT("17 size_t is unsigned int",sizeof(size_t)==sizeof(unsigned int));
    /* this is true for C99, but not for C90. */
    EXPECT("18 a%b has the same sign as a",((-10%3)==-1) && ((10%-3)==1));

    /* suggested by nos */
    EXPECT("19-1 char<short",sizeof(char)<sizeof(short));
    EXPECT("19-2 short<int",sizeof(short)<sizeof(int));
    EXPECT("19-3 int<long",sizeof(int)<sizeof(long));
    EXPECT("20 ptrdiff_t and size_t have the same size",(sizeof(ptrdiff_t)==sizeof(size_t)));
#if 0
    {
        /* suggested by R. */
        /* this crashed on TC 3.0++, compact. */
        char buf[10];
        EXPECT("21 You can use snprintf to append a string",
               (snprintf(buf,10,"OK"),snprintf(buf,10,"%s!!",buf),strcmp(buf,"OK!!")==0));
    }
#endif

    EXPECT("21 Evaluation is left to right",
           (ltr_fun(1)*ltr_fun(2)*ltr_fun(3)*ltr_fun(4),ltr_result==1234));

    {
    #ifdef __STDC_IEC_559__
    int STDC_IEC_559_is_defined=1;
    #else 
    /* This either means, there is no FP support
     *or* the compiler is not C99 enough to define  __STDC_IEC_559__
     *or* the FP support is not IEEE compliant. */
    int STDC_IEC_559_is_defined=0;
    #endif
    EXPECT("22 floating point is always IEEE",STDC_IEC_559_is_defined);
    }

    printf("From what I can say with my puny test cases, you are %d%% mainstream\n",100-(100*count)/total);
    return 0;
}

아, 그리고 나는 사람들이 이것을 읽을 때 내 blabber를 편집하고 싶어한다고 생각했기 때문에 처음부터이 커뮤니티 위키를 만들었습니다.

업데이트 귀하의 의견에 감사드립니다. 귀하의 답변에서 몇 가지 사례를 추가했으며 Greg가 제안한 것처럼 github를 설정할 수 있는지 확인할 것입니다.

업데이트 : 나는 이것을 위해 github repo를 만들었습니다. 파일은 "gotcha.c"입니다.

여기에서 패치 또는 새로운 아이디어로 답변 해주세요. 여기에서 논의하거나 명확히 할 수 있습니다. 그런 다음 gotcha.c로 병합합니다.


7
DOS의 중간 모델을 고려하십시오. 함수는 여러 세그먼트에 저장 될 수 있으므로 함수 포인터의 길이는 32 비트입니다. 그러나 데이터는 단일 세그먼트에만 저장되므로 데이터 포인터의 길이는 16 비트에 불과합니다. void *는 데이터 포인터이므로 폭이 16 비트이므로 함수 포인터를 하나에 맞출 수 없습니다. c-jump.com/CIS77/ASM/Directives/D77_0030_models.htm을 참조하십시오 .
다윗은 주어

6
아마도이 코드를 github.com 이나 다른 곳에 올려 놓으면 사람들이 쉽게 패치를 기여할 수있을 것입니다.
Greg Hewgill

1
여기에 많은 것들이 도움이 될 것입니다 : stackoverflow.com/questions/367633/…
Martin York

4
POSIX에서는 함수 포인터가 void *와 동일한 표현을 가져야하며 정보 손실없이 변환 (캐스트 사용) 할 수 있어야합니다. 그 이유 중 하나는 dlsym()void * 를 반환하지만 데이터 포인터와 함수 포인터 모두를위한 것입니다. 따라서 이것에 의존하는 것이 그렇게 나쁘지 않을 수 있습니다.
jilles 2010-08-11

3
@tristopia : Point 15는 여기에 있습니다. 많은 초보자들이 데이터가 지속적으로 압축되지 않고 특정 경계에 맞춰져 있다는 사실에 종종 놀라는 경우가 많기 때문입니다. 그들은 회원 순서를 변경하고 다른 개체 크기를 얻을 때 당황합니다. 또한 패킹은 많은 최신 마이크로 컨트롤러 또는 임베디드 장치에서 기본 모드입니다. 내 AVR Atmega 및 TurboC / MSDOS 출력도 압축되어 있습니다. MSDOS는 여전히 산업 응용 분야에서 사용됩니다.
Nordic Mainframe

답변:


91

다음을 포함한 하위 표현식 평가 순서

  • 함수 호출의 인수 및
  • 연산자의 피연산자 (예를 들어, +, -, =, *, /)를 제외한 :
    • 이항 논리 연산자 ( &&||),
    • 삼항 조건 연산자 ( ?:)
    • 쉼표 연산자 ( ,)

지정되지 않음

예를 들면

  int Hello()
  {
       return printf("Hello"); /* printf() returns the number of 
                                  characters successfully printed by it
                               */
  }

  int World()
  {
       return printf("World !");
  }

  int main()
  {

      int a = Hello() + World(); //might print Hello World! or World! Hello
      /**             ^
                      | 
                Functions can be called in either order
      **/
      return 0;
  } 

1
저는 항상 함수 매개 변수에 대해 알고 있었지만 연산자 측면에서 생각 해본 적이 없었습니다. ... ... 생산 환경에서 이와 같은 코드를 작성하는 것을 본 적이 있다면 젖은 국수로 당신을 때릴 것입니다.
riwalk

3
@Billy :하지만 연산자의 원시 버전에만 해당됩니다.
Dennis Zickefoose 2010 년

1
@Dennis : 사실입니다. (Effective / MoreEffective C ++의 항목이 이러한 항목을 오버로드하지 않는 이유는 무엇입니까? (작성중인 경우 boost::spirit제외))
Billy ONeal

1
@ 다니엘 : 무슨 말을 하려는지 잘 모르겠습니다. 그것은 당신의 클래스의 사용자들만이 잘못 될 수 있기 때문에 연산자를 오버로드해도 좋다고 제안하는 것처럼 들리며, 만약 당신이 직접적인 C ++로 작성하지 않는다면 그것은 중요하지 않습니다. 어느 쪽도 전혀 의미가 없습니다.
Dennis Zickefoose 2010 년

2
@ user420536 : 동작이 지정되지 않았지만 정의되지 않았습니다. 예, 예제는 Hello World! 또는 세계! 안녕하세요. +연산자 의 피연산자 평가 순서가 지정되지 않았기 때문에 지정되지 않았습니다 (컴파일러 작성자는 동작을 문서화 할 필요가 없음). 시퀀스 포인트 규칙을 위반하지 않습니다 .
Prasoon Saurav

38

sdcc 29.7 / ucSim / Z80

We like to think that:
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..19-2 short<int
   but 'sizeof(short)<sizeof(int)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
   but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
From what I can say with my puny test cases, you are Stop at 0x0013f3: (106) Invalid instruction 0x00dd

printf가 충돌합니다. "O_O"


gcc 4.4@x86_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 79% mainstream

gcc 4.4@x86_64-suse-linux (-O2)

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 82% mainstream

clang 2.7@x86_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..21a Function Arguments are evaluated right to left
but '(gobble_args(0,ltr_fun(1),ltr_fun(2),ltr_fun(3),ltr_fun(4)),ltr_result==4321)' is false.
ltr_result is 1234 in this case
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 72% mainstream

open64 4.2.3@x86_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..21a Function Arguments are evaluated right to left
but '(gobble_args(0,ltr_fun(1),ltr_fun(2),ltr_fun(3),ltr_fun(4)),ltr_result==4321)' is false.
ltr_result is 1234 in this case
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 75% mainstream

인텔 11.1@x86_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..21a Function Arguments are evaluated right to left
but '(gobble_args(0,ltr_fun(1),ltr_fun(2),ltr_fun(3),ltr_fun(4)),ltr_result==4321)' is false.
ltr_result is 1234 in this case
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 75% mainstream

Turbo C ++ / DOS / 소형 메모리

We like to think that:
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..16 malloc()=NULL means out of memory
but '(malloc(0)!=NULL)' is false.
..19-2 short<int
but 'sizeof(short)<sizeof(int)' is false.
..22 floating point is always IEEE
but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
From what I can say with my puny test cases, you are 81% mainstream

터보 C ++ / DOS / 중간 메모리

We like to think that:
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..10 void* can store function pointers
but 'sizeof(void*)>=sizeof(void(*)())' is false.
..16 malloc()=NULL means out of memory
but '(malloc(0)!=NULL)' is false.
..19-2 short<int
but 'sizeof(short)<sizeof(int)' is false.
..22 floating point is always IEEE
but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
From what I can say with my puny test cases, you are 78% mainstream

Turbo C ++ / DOS / 컴팩트 메모리

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..16 malloc()=NULL means out of memory
but '(malloc(0)!=NULL)' is false.
..19-2 short<int
but 'sizeof(short)<sizeof(int)' is false.
..20 ptrdiff_t and size_t have the same size
but '(sizeof(ptrdiff_t)==sizeof(size_t))' is false.
..22 floating point is always IEEE
but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
From what I can say with my puny test cases, you are 75% mainstream

cl65 @ Commodore PET (부스 에뮬레이터)

대체 텍스트


나중에 업데이트 할 예정입니다.


Windows XP의 Borland C ++ Builder 6.0

..04 a char is signed
   but 'CHAR_MIN==SCHAR_MIN' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09 overshifting is *always* okay
   but '(1<<BITS_PER_INT)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..16 malloc()=NULL means out of memory
   but '(malloc(0)!=NULL)' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 71% mainstream

Visual Studio Express 2010 C ++ CLR, Windows 7 64 비트

(CLR 컴파일러는 순수 C를 지원하지 않으므로 C ++로 컴파일해야 함)

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 78% mainstream

MINGW64 (gcc-4.5.2 프리 릴리즈)

-http : //mingw-w64.sourceforge.net/

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..05a long has at least the size of pointers
   but 'sizeof(long)>=sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 67% mainstream

64 Windows가 LLP64 모델을 사용하여 비트 : 모두 intlong32 비트 수단으로 정의되는 어느 포인터에 대해 충분히입니다.


avr-gcc 4.3.2 / ATmega168 (Arduino Diecimila)

실패한 가정은 다음과 같습니다.

..14 i++ is structly left to right
..16 malloc()=NULL means out of memory
..19-2 short<int
..21 Evaluation is left to right
..22 floating point is always IEEE

Atmega168에는 16 비트 PC가 있지만 코드와 데이터는 별도의 주소 공간에 있습니다. 더 큰 Atmega에는 22 비트 PC가 있습니다!.


MacOSX 10.6의 gcc 4.2.1, -arch ppc로 컴파일 됨

We like to think that:
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits come always first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 78% mainstream


32
그리고 또 다른 가정을 확인했습니다. 터미널 라인에 80자를 넣을 수 있다는 것입니다.
Mike Seymour

3
sizeof(void*)>=sizeof(void(*)())==보다 더 관련이 있습니다. 우리가 신경 쓰는 것은 "무효 포인터에 함수 포인터를 저장할 수 있는가"입니다. 따라서 테스트해야 할 가정은 a void*적어도 함수 포인터만큼 큰지 여부 입니다.
jalf 2013-08-11

1
환경이 POSIX 호환 경우, 당신은 괜찮해야합니다 sizeof(void*)>=sizeof(void(*)())- 볼 opengroup.org/onlinepubs/009695399/functions/dlsym.html
다니엘 Earwicker

26

오래 전에 저는 교과서에서 C를 가르치고있었습니다.

printf("sizeof(int)=%d\n", sizeof(int));

샘플 질문으로. 때문에, 학생 실패 sizeof유형의 수율 값이 size_t아니라 int, int이 구현에 16 비트이고 size_t32이고, 그것은 빅 엔디안했다. (플랫폼은 680x0 기반 매킨토시의 Lightspeed C였습니다. 오래 전이라고 말했습니다.)


7
+1은 이러한 종류의 가장 일반적이고 일반적으로 간과되는 오류 중 하나를 지적합니다.
R .. GitHub STOP HELPING ICE

4
이것은 또한 64 비트 시스템에서 발생합니다. 여기서 size_t는 64 비트이고 int는 거의 항상 더 짧습니다. size_t가 있기 때문에 Win64는 여전히 더 이상 unsigned long long합니다. 테스트 17로 추가됨.
Nordic Mainframe

불행히도 Microsoft의 C 런타임은 크기가 지정된 정수에 대한 z수정자를 지원하지 않으며 일부 플랫폼에서도 지원되지 않습니다. 따라서 개체의 인쇄 된 크기를 형식화하거나 캐스팅하는 안전한 휴대용 방법이 없습니다. size_tlong long
Phil Miller

15

사람들이 하는 ++--가정 을 포함해야합니다 .

a[i++]= i;

예를 들어,는 구문 적으로 합법적이지만 추론 할 수없는 항목이 너무 많으면 다양한 결과를 생성합니다.

++(또는 --)과 두 번 이상 발생하는 변수가있는 문 은 문제입니다.


그리고 그것은 너무 일반적인 질문이기도합니다!
Matthieu M.

8

매우 흥미로운!

내가 생각할 수있는 다른 것들은 다음을 확인하는 데 유용 할 수 있습니다.

  • 함수 포인터와 데이터 포인터가 동일한 주소 공간에 있습니까? (DOS 스몰 모드와 같은 Harvard 아키텍처 머신에서 중단됩니다. 어떻게 테스트할지 모르겠습니다.)

  • NULL 데이터 포인터를 가져 와서 적절한 정수 유형으로 캐스트하면 숫자 값이 0입니까? (실제로 오래된 일부 기계에서 중단 --- http://c-faq.com/null/machexamp.html 참조 ) 함수 포인터도 마찬가지입니다. 또한 값이 다를 수 있습니다.

  • 해당 저장소 개체의 끝을지나 포인터를 증가했다가 다시 되 돌리면 합리적인 결과가 발생합니까? (나는 이것이 실제로 깨지는 어떤 기계도 모르지만 C 스펙은 (a) 배열의 내용이나 (b) 요소를 가리 키지 않는 포인터에 대해 생각 조차 할 수 없다고 생각 합니다. 배열 바로 뒤 또는 (c) NULL. http://c-faq.com/aryptr/non0based.html 참조 )

  • 서로 다른 저장소 개체에 대한 두 포인터를 <및>와 비교하면 일관된 결과가 생성됩니까? (나는 이것이 이국적인 세그먼트 기반 머신에서 깨지는 것을 상상할 수 있습니다. 스펙은 그러한 비교를 금지하므로 컴파일러는 세그먼트 부분이 아닌 포인터의 오프셋 부분 만 비교할 자격이 있습니다.)

흠. 좀 더 생각해 보겠습니다.

편집 : 우수한 C FAQ에 대한 명확한 링크를 추가했습니다.


2
덧붙여서, 얼마 전에 Clue ( cluecc.sourceforge.net ) 라는 실험 프로젝트 를 수행하여 C를 Lua, Javascript, Perl, LISP 등으로 컴파일 할 수있었습니다. C 표준에서 정의되지 않은 동작을 무자비하게 이용하여 포인터가 작동하도록했습니다. . 이 테스트를 시도하는 것이 흥미로울 수 있습니다.
다윗은 주어

1
IIRC C를 사용하면 개체의 끝을 넘어서 포인터를 1 씩 증가시킬 수 있습니다 . 그러나 객체의 시작 이전 위치로 감소시키는 것은 허용되지 않습니다.
R .. GitHub STOP HELPING ICE

@아르 자형. C ++에서도 동일합니다. 포인터를 정수로 취급하지 않는 CPU에서 포인터를 증가 시키면 오버플로가 발생하면 추가 증가가 중단 될 수 있습니다.
jalf 2014-08-11

5

나는 당신이 "잘못된"가정의 매우 다른 두 종류를 구별하기 위해 노력해야한다고 생각한다. 좋은 절반 (오른쪽 시프트 및 부호 확장, ASCII 호환 인코딩, 메모리는 선형, 데이터 및 함수 포인터가 호환 됨 등)은 대부분의 C 코더가 만들 수 있는 매우 합리적인 가정이며 표준의 일부로 포함될 수도 있습니다. C가 현재 설계되고 있고 기존 IBM 정크가없는 경우. 나머지 절반 (메모리 앨리어싱과 관련된 것, 입력 및 출력 메모리가 겹칠 때 라이브러리 함수의 동작, 포인터가 맞 int거나 사용할 수 있는 것과 같은 32 비트 가정)malloc 프로토 타입이 없으면이 호출 규칙은 가변 및 비가 변 함수에 대해 동일합니다. ...) 현대 컴파일러가 수행하려는 최적화와 충돌하거나 64 비트 시스템 또는 기타 새로운 기술로의 마이그레이션과 충돌합니다.


그것은 단지 "IBM 쓰레기"가 아닙니다 (IBM이 쓰레기라는 것에 동의합니다). 오늘날 많은 임베디드 시스템에는 유사한 문제가 있습니다.
rmeador

명확히 malloc말하면, 프로토 타입없이 사용 한다는 것은를 포함하지 않음을 의미 <stdlib.h>하므로 64 비트를 지원하려면 no-no malloc가 기본값으로 설정됩니다 int malloc(int).
Joey Adams

기술적으로 <stdlib.h>정의하는 다른 헤더를 포함 하고 올바른 프로토 타입으로 직접 size_t선언 malloc하는 한 포함하지 않아도됩니다 .
R .. GitHub의 STOP 돕기 ICE

5

여기에 재미있는 것이 있습니다.이 기능에 어떤 문제가 있습니까?

float sum(unsigned int n, ...)
{
    float v = 0;
    va_list ap;
    va_start(ap, n);
    while (n--)
        v += va_arg(ap, float);
    va_end(ap);
    return v;
}

[답변 (rot13) : Inevnqvp nethzragf borl gur byq X & E cebzbgvba ehyrf, juvpu zrnaf lbh pnaabg hfr 'sybng'(be 'pune'be 'fubeg')) va in_net! Naq gur pbzcvyre vf erdhverq abg gb gerng guvf nf n pbzcvyr-gvzr reebe. (TPP qbrf rzvg n jneavat, gubhtu.)]


오, 그거 좋은데. clang 2.7은 이것을 먹고 경고없이 완전한 넌센스를 생성합니다.
Nordic Mainframe

va_arg는 매크로이고 while 루프는 아마도 많은 것 중 첫 번째 문만 실행하면 확장됩니다.
Maister 2010-08-29

아니요 (그렇게되면 구현의 버그가됩니다).
zwol 2010 년

5
EXPECT("## pow() gives exact results for integer arguments", pow(2, 4) == 16);

또 다른 하나는 fopen. 대부분의 프로그래머는 텍스트와 바이너리가 같거나 (Unix) 텍스트 모드가 \r문자를 추가 (Windows) 한다고 가정합니다 . 그러나 C는 고정 너비 레코드를 사용하는 시스템으로 이식되었습니다 fputc('\n', file). 텍스트 파일에서 파일 크기가 레코드 길이의 배수가 될 때까지 공백이나 무언가를 추가하는 것을 의미합니다.

그리고 내 결과는 다음과 같습니다.

x86-64의 gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
From what I can say with my puny test cases, you are 78% mainstream

실제로 pow(2, n)비트 연산과 결합 된 코드를 보았습니다 .
dan04

4

그들 중 일부는 가정이 유지되지 않는 구현에서 프로그램이 충돌 할 가능성이 있기 때문에 C 내부에서 쉽게 테스트 할 수 없습니다.


"포인터 값 변수로 무엇이든 할 수 있습니다. 역 참조 할 경우 유효한 포인터 값만 포함하면됩니다."

void noop(void *p); /* A no-op function that the compiler doesn't know to optimize away */
int main () {
    char *p = malloc(1);
    free(p);
    noop(p); /* may crash in implementations that verify pointer accesses */
    noop(p - 42000); /* and if not the previous instruction, maybe this one */
}

unsigned char트랩 표현을 가질 수 있는 정수 및 부동 소수점 유형 (제외 ) 과 동일 합니다.


"정수 계산이 둘러싸여 있습니다. 따라서이 프로그램은 큰 음의 정수를 인쇄합니다."

#include <stdio.h>
int main () {
    printf("%d\n", INT_MAX+1); /* may crash due to signed integer overflow */
    return 0;
}

(C89 만 해당) "끝에서 떨어져도 괜찮습니다 main."

#include <stdio.h>
int main () {
    puts("Hello.");
} /* The status code is 7 on many implementations. */

2
구체적인 예 :로 컴파일 gcc -ftrapv -O하면 출력 We like to think that:뒤에Aborted
caf

@caf : "이 옵션은 더하기, 빼기, 곱하기 연산에서 서명 된 오버플로에 대한 트랩을 생성합니다." 알아서 반갑습니다, 감사합니다.
Gilles 'SO- 그만 사악한

1
마지막 것은 C ++ (98, 03 및 0x)에서도 괜찮으며 암시 적으로 0을 반환합니다.
jalf

ANSI C 이전에 이것을 허용했고 C99도 마찬가지이기 때문에 불쾌합니다.
Joshua

@Joshua : AFAIK는 반환시 ANSI C 이전과 C89 사이에 아무런 차이가 없습니다 main: 프로그램은 정확하지만 정의되지 않은 종료 상태를 반환합니다 (C89 §2.1.2.2). 많은 구현 (예 : gcc 및 이전 유닉스 컴파일러)을 통해 해당 시점에서 특정 레지스터에 있던 모든 것을 얻을 수 있습니다. 프로그램은 일반적으로 종료 상태를 확인하는 메이크 파일 또는 기타 환경에서 사용될 때까지 작동합니다.
Gilles 'SO- 그만 악한'

4

아직 의미가없는 고전적인 이식성 가정은

  • 정수 유형의 크기에 대한 가정
  • 엔디안

4
"엔디안이 있습니다"를 포함한 "엔디안": 미들 엔디안 머신이 있으며 표준은 short2 바이트 0248ace 및 fdb97531로 fedcab9876543210 (즉, 16 개의 이진수) 값을 저장하는 것과 같은 이상한 일을 허용 합니다.
Gilles 'SO- 그만 사악한

예 엔디안은 확실히 혼합 / 중간 엔디안과 크고 작은 엔디안을 포함합니다. 맞춤형 하드웨어로 이동하면 모든 버스에서 원하는 엔디안을 가질 수 있습니다.
jk.

미들 엔디안은 PDP 엔디안으로 알려져 있습니다. Gilles는 TCP / IP를 구현하는 데 골칫거리가 될 수 있지만 더 이상한 것을 설명합니다.
Joshua

@Gilles : 미들 엔디안 ... 그거 개발하지 않아서 기뻐요. (하지만 지금은 미들 엔디안 네트워킹 프로젝트를 수행하라는 요청을 받게 될 것입니다. 확신합니다) ...
Paul Nathan

ARM FPE는 <high ​​quad> <low quad> 쌍으로 저장되는 middle-endian double을 사용했지만 각 쿼드 내부의 비트 순서가 잘못되었습니다. (다행히이 ARM VFP 더 이상이 작업을 수행하지 않습니다는.)
데이비드을 감안할 때

4
  • 부동 소수점 표현으로 인한 이산화 오류. 예를 들어 표준 공식을 사용하여 2 차 방정식을 풀거나 유한 차분을 근사화하거나 표준 공식을 사용하여 분산을 계산하는 경우 유사 숫자 간의 차이 계산으로 인해 정밀도가 손실됩니다. 선형 시스템을 해결하는 Gauß 알고리즘은 반올림 오류가 누적되기 때문에 나쁘기 때문에 QR 또는 LU 분해, Cholesky 분해, SVD 등을 사용합니다. 부동 소수점 수의 추가는 연관성이 없습니다. 비정규, 무한 및 NaN 값이 있습니다. a + bab .

  • 문자열 : 문자, 코드 포인트 및 코드 단위의 차이. 다양한 운영 체제에서 유니 코드를 구현하는 방법 유니 코드 인코딩. C ++에서는 임의의 유니 코드 파일 이름을 가진 파일을 이식 가능한 방식으로 열 수 없습니다.

  • 스레딩이없는 경우에도 경쟁 조건 : 파일이 있는지 여부를 테스트하면 결과가 언제든지 유효하지 않을 수 있습니다.

  • ERROR_SUCCESS = 0


4

정수 크기 확인을 포함합니다. 대부분의 사람들은 int가 short보다 크다고 생각하고 char보다 크다고 생각합니다. 그러나 다음은 모두 거짓 일 수 있습니다.sizeof(char) < sizeof(int); sizeof(short) < sizeof(int); sizeof(char) < sizeof(short)

이 코드는 실패 할 수 있습니다 (정렬되지 않은 액세스에 충돌)

unsigned char buf[64];

int i = 234;
int *p = &buf[1];
*p = i;
i = *p;

이 코드가 C ++에서 실패합니까? IIRC, 모든 유형으로 캐스트 될 수있는 char *의 경우를 제외하고 관련없는 유형간에 포인터를 캐스트하는 것은 불법입니다 (또는 그 반대입니까?).
rmeador

1
당신은 int *p = (int*)&buf[1];C ++로만 할 수 있고 , 사람들은 그것도 작동 할 것으로 기대합니다.
nos

@nos, 예, 실패 할 수 있지만 실패는 충돌이므로 그의 프로그램은 해당 프로그램을 테스트 할 수 없습니다. :(
Joshua

1
sizeof(char) < sizeof(int)필수입니다. 예를 들어, fgetc ()는 문자 값을 int로 변환 된 부호없는 문자 또는 EOF음수 값으로 반환합니다 . unsigned char패딩 비트가 없을 수 있으므로이 작업을 수행 할 수있는 유일한 방법은 int를 char보다 크게 만드는 것입니다. 또한 (대부분의 버전) C 사양에서는 -32767..32767 범위의 값을 int에 저장할 수 있어야합니다.
jilles 2010 년

@illes는 여전히 32 비트 문자와 32 비트 정수를 가진 DSP가 있습니다.
nos

3

내장 데이터 유형에 대한 몇 가지 사항 :

  • char그리고 signed char두 가지 유형은 (는 달리 실제로 int하고 signed int있는 같은 부호있는 정수 유형 참조).
  • 2의 보수를 사용하는 데 부호있는 정수는 필요하지 않습니다. 1의 보수와 부호 + 크기도 음수의 유효한 표현입니다. 이것은 음수를 포함하는 비트 연산을 구현 정의 합니다.
  • 범위를 벗어난 정수를 부호있는 정수 변수에 할당하는 경우 동작은 구현 정의 입니다.
  • C90에서 -3/5반환 할 수 0또는 -1. 한 피연산자가 음수 인 경우 0으로 반올림하는 것은 C99에서 위쪽으로, C ++ 0x에서 위쪽으로 만 보장됩니다.
  • 내장 유형에 대한 정확한 크기 보장은 없습니다. 같은 표준은 최소한의 요구 사항을 포함 int갖고 적어도 16 비트 A는 long갖고 적어도 A는, 32 개 비트를 long long갖고 적어도 64 비트. A float는 6 개 이상의 최상위 10 진수를 올바르게 나타낼 수 있습니다. A double는 최소 10 개의 최상위 10 진수를 올바르게 나타낼 수 있습니다.
  • IEEE 754는 부동 소수점 숫자를 나타내는 데 필수가 아닙니다.

물론, 대부분의 컴퓨터에는 2의 보수와 IEEE 754 부동이 있습니다.


범위를 벗어난 정수 할당이 정의되지 않은 동작보다 구현 정의되는 데 어떤 가치가 있는지 궁금합니다. 일부 플랫폼에서 이러한 요구 사항은 컴파일러가 int mult(int a,int b) { return (long)a*b;}[예 : int32 비트이지만 레지스터이고 long64 인 경우]에 대한 추가 코드를 생성하도록 강제합니다 . 이러한 요구 사항이 없다면, 가장 빠른 구현의 "자연"동작을 long l=mult(1000000,1000000);설정합니다 l동일 1000000000000그가에 대한 "불가능"값에도 불구하고 int.
supercat 2014-01-09

3

이건 어때:

데이터 포인터는 유효한 함수 포인터와 같을 수 없습니다.

이것은 모든 플랫 모델, MS-DOS TINY, LARGE 및 HUGE 모델의 경우 TRUE, MS-DOS SMALL 모델의 경우 false, MEDIUM 및 COMPACT 모델의 경우 거의 항상 false입니다 (로드 주소에 따라 다름, 정말 오래된 DOS가 필요합니다. 사실로 만드십시오).

이것에 대한 테스트를 작성할 수 없습니다

그리고 더 나쁜 것은 ptrdiff_t로 캐스트 된 포인터를 비교할 수 있다는 것입니다. 이것은 MS-DOS LARGE 모델에 해당되지 않습니다. LARGE와 HUGE의 유일한 차이점은 HUGE가 포인터를 정규화하기 위해 컴파일러 코드를 추가한다는 것입니다.

이 폭탄이 터지는 환경은 64K보다 큰 버퍼를 할당하지 않기 때문에 테스트를 작성할 수 없으므로이를 보여주는 코드가 다른 플랫폼에서 충돌 할 수 있습니다.

이 특정 테스트는 현재 없어진 하나의 시스템을 통과합니다 (malloc의 내부에 따라 다름).

  char *ptr1 = malloc(16);
  char *ptr2 = malloc(16);
  if ((ptrdiff_t)ptr2 - 0x20000 == (ptrdiff_t)ptr1)
      printf("We like to think that unrelated pointers are equality comparable when cast to the appropriate integer, but they're not.");

3

편집 : 프로그램의 마지막 버전으로 업데이트 됨

Solaris-SPARC

32 비트의 gcc 3.4.6

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09 overshifting is *always* okay
   but '(1<<BITS_PER_INT)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 72% mainstream

64 비트의 gcc 3.4.6

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09 overshifting is *always* okay
   but '(1<<BITS_PER_INT)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 68% mainstream

및 SUNStudio 11 32 비트

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
From what I can say with my puny test cases, you are 79% mainstream

및 SUNStudio 11 64 비트

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
From what I can say with my puny test cases, you are 75% mainstream

2

텍스트 모드 ( fopen("filename", "r"))를 사용하여 모든 종류의 텍스트 파일을 읽을 수 있습니다.

이 동안 해야 잘 이론 연구에서, 당신은 또한 사용하는 경우 ftell()코드에서, 그리고 텍스트 파일을 UNIX 스타일의 라인 엔딩을 가지고, 윈도우 표준 라이브러리의 일부 버전에서, ftell()종종 잘못된 값을 반환합니다. 해결책은 대신 바이너리 모드 ( fopen("filename", "rb"))를 사용하는 것입니다.


1

AIX 5.3의 gcc 3.3.2 (예, gcc를 업데이트해야 함)

We like to think that:
..04 a char is signed
   but 'CHAR_MIN==SCHAR_MIN' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits come always first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..16 malloc()=NULL means out of memory
   but '(malloc(0)!=NULL)' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 71% mainstream

1

어떤 사람들이 C ++에서 할 수 있다는 가정은 a struct가 C에서 할 수있는 일로 제한된다는 것입니다. 사실 C ++에서 a structclass기본적으로 모든 것이 공개된다는 점을 제외하면 a와 같습니다 .

C ++ 구조체 :

struct Foo
{
  int number1_;  //this is public by default


//this is valid in C++:    
private: 
  void Testing1();
  int number2_;

protected:
  void Testing2();
};

1

다른 시스템의 표준 수학 함수는 동일한 결과를 제공하지 않습니다.


1

32 비트 x86의 Visual Studio Express 2010.

Z:\sandbox>cl testtoy.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

testtoy.c
testtoy.c(54) : warning C4293: '<<' : shift count negative or too big, undefined
 behavior
Microsoft (R) Incremental Linker Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:testtoy.exe
testtoy.obj

Z:\sandbox>testtoy.exe
We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 78% mainstream

1

Codepad.org ( C++: g++ 4.1.2 flags: -O -std=c++98 -pedantic-errors -Wfatal-errors -Werror -Wall -Wextra -Wno-missing-field-initializers -Wwrite-strings -Wno-deprecated -Wno-unused -Wno-non-virtual-dtor -Wno-variadic-macros -fmessage-length=0 -ftemplate-depth-128 -fno-merge-constants -fno-nonansi-builtins -fno-gnu-keywords -fno-elide-constructors -fstrict-aliasing -fstack-protector-all -Winvalid-pch)를 통해 .

Codepad에는 stddef.h. 경고를 오류로 사용하는 코드 패드로 인해 테스트 9를 제거했습니다. 나는 또한 count어떤 이유로 이미 정의되었으므로 변수의 이름을 변경했습니다 .

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
From what I can say with my puny test cases, you are 84% mainstream

1

과도한 양만큼 오른쪽으로 이동하는 것은 어떻습니까? 표준에서 허용합니까 아니면 테스트 할 가치가 있습니까?

표준 C는 다음 프로그램의 동작을 지정합니까?

void print_string (char * st)
{
  char ch;
  while ((ch = * st ++)! = 0)
    퍼치 (ch); / * 이것이 정의되었다고 가정 * /
}
int main (void)
{
  print_string ( "Hello");
  반환 0;
}

내가 사용하는 하나 이상의 컴파일러에서 print_string에 대한 인수가 "char const *" 가 아니면 해당 코드는 실패합니다 . 표준이 그러한 제한을 허용합니까?

일부 시스템에서는 정렬되지 않은 'int'에 대한 포인터를 생성 할 수 있고 다른 시스템은 그렇지 않습니다. 테스트할만한 가치가 있습니다.


C89 §3.3.7 : "오른쪽 피연산자의 값이 음수이거나 승격 된 왼쪽 피연산자의 비트 너비보다 크거나 같으면 동작이 정의되지 않습니다." ( <<및 모두에 적용됨 >>). C99는 §6.5.7-3에서 동일한 언어를 사용합니다.
Gilles 'SO- 사악한 중지'

putch(왜 표준을 사용하지 않았 putchar습니까?) 외에도 프로그램에서 정의되지 않은 동작을 볼 수 없습니다. C89 §3.1.4는 "문자열 리터럴이 […] 유형 '문자 배열'을 갖습니다"(참고 : no const)를 지정하고 "프로그램이 문자열 리터럴 […]을 수정하려고하면 동작이 정의되지 않습니다"라고 지정합니다. . 그 컴파일러는 무엇이며이 프로그램을 어떻게 번역합니까?
Gilles 'SO- 그만 사악함'2010-08-14

2
C ++에서 문자 상수는 char [] 가 아니라 const char []입니다. 그러나 ...이 사용 당신은 숯불 *이 예상 유형 오류가 발생하지 않은 상황에서 문자열 상수를 사용할 수 있도록 타입 시스템에서 특정 구멍을합니다. 이로 인해 print_string ( "foo")는 작동하지만 print_string ( "foo"+0)은 작동하지 않는 상황이 발생했습니다. 이는 특히 C ++ 컴파일러를 사용하여 기본적으로 C 파일을 컴파일하는 환경에서 매우 혼란 스러웠습니다. 새로운 컴파일러에서는 구멍이 제거되었지만 여전히 많은 오래된 컴파일러가 있습니다. AFAIK C99는 여전히 문자열 상수를 char []로 정의합니다.
다윗은 주어

1
Microchip PIC 컨트롤러 시리즈 용 HiTech 컴파일러에서 스토리지 한정자가없는 포인터는 RAM 만 가리킬 수 있습니다. const 한정 포인터는 RAM 또는 ROM을 가리킬 수 있습니다. 상수가 아닌 포인터는 코드에서 직접 역 참조됩니다. const 한정 포인터는 라이브러리 루틴을 통해 역 참조됩니다. 특정 유형의 PIC에 따라 상수가 아닌 포인터는 1 바이트 또는 2 바이트입니다. const 한정된 것은 2 또는 3입니다. ROM은 RAM보다 훨씬 많기 때문에 ROM에 상수를 갖는 것이 일반적으로 좋습니다.
supercat

@David 기븐 : 이전 댓글도 참고하세요. 나는 하드웨어 스토리지 클래스를 표시하기 위해 "const"이외의 한정자를 사용하는 컴파일러를 선호합니다. HiTech 컴파일러는 스토리지 클래스 할당에 다소 성가신 단점이 있습니다 (예 : "컴포넌트 크기"가 바이트 인 데이터 항목 또는 256 바이트를 초과하는 데이터 항목은 "큰"세그먼트로 이동합니다. 다른 데이터 항목은 " 정의 된 모듈에 대한 bss "세그먼트, 모듈의 모든"bss "항목은 256 바이트 이내 여야합니다. 256 바이트보다 약간 짧은 배열은 실제 성가신 일이 될 수 있습니다.
supercat 2010-08-15

0

참고로, C 기술을 Java로 번역해야하는 사람들을 위해 몇 가지 문제가 있습니다.

EXPECT("03 a char is 8 bits",CHAR_BIT==8);
EXPECT("04 a char is signed",CHAR_MIN==SCHAR_MIN);

Java에서 char은 16 비트이며 서명됩니다. 바이트는 8 비트이며 부호가 있습니다.

/* not true for Windows-64 */
EXPECT("05a long has at least the size of pointers",sizeof(long)>=sizeof(void*));

long은 항상 64 비트이고 참조는 32 비트 또는 64 비트 일 수 있습니다 (32GB를 초과하는 앱이 두 개 이상있는 경우) 64 비트 JVM은 일반적으로 32 비트 참조를 사용합니다.

EXPECT("08 overshifting is okay",(1<<bits_per_int)==0);
EXPECT("09 overshifting is *always* okay",(1<<BITS_PER_INT)==0);

시프트는 i << 64 == i == i << -64, i << 63 == i << -1이되도록 마스킹됩니다.

EXPECT("13 The smallest bits always come first",(t=0x1234,0x34==*(char*)&t));

ByteOrder.nativeOrder ()는 BIG_ENDIAN 또는 LITTLE_ENDIAN 일 수 있습니다.

EXPECT("14 i++ is strictly left to right",(i=0,a[i++]=i,a[0]==1));

i = i++ 절대 변하지 않는다 i

/* suggested by David Thornley */
EXPECT("17 size_t is unsigned int",sizeof(size_t)==sizeof(unsigned int));

콜렉션 및 배열의 ​​크기는 JVM이 32 비트인지 64 비트인지에 관계없이 항상 32 비트입니다.

EXPECT("19-1 char<short",sizeof(char)<sizeof(short));
EXPECT("19-2 short<int",sizeof(short)<sizeof(int));
EXPECT("19-3 int<long",sizeof(int)<sizeof(long));

char은 16 비트, short는 16 비트, int는 32 비트, long은 64 비트입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.