C에서의 골프 팁


137

C 골프에 대한 일반적인 팁은 무엇입니까? 나는 일반적으로 C에 다소 특정한 코드 골프 문제에 적용될 수있는 아이디어를 찾고 있습니다 (예 : "댓글 제거"는 답이 아닙니다). 답변 당 하나의 팁을 게시하십시오. 또한 팁이 C89 및 / 또는 C99에 적용되고 특정 컴파일러에서만 작동하는지 포함하십시오.


8
가장 큰 단일 문장 힌트는 다음과 같습니다. IOCCC에 제출 된 우승 코드를 읽으십시오.
vsz

답변:


107

비트 XOR을 사용하여 정수 사이의 불평등을 확인하십시오.

if(a^b)대신 if(a!=b)1자를 저장합니다.


73
a-b같은 효과를줍니다.
ugoren

22
마찬가지로 a*b대신 사용할 수 있습니다 a&&b(우선 순위가 다르거 나 나쁘거나 나쁘지 않을 수 있음). 만약 당신이 / = -b를 알고 있다면 (예를 들어, 부호가 없다) a||b==a+b
walpen

3
더 나은 아직 엘비스 운영자와 결합 ?:(대신 경우의) : exemple를 위해 뭔가를 할 수있는 경우의 differents : a^b?_diff_:;
올리비에 Dulac

1
@OlivierDulac 거짓 분기 인 경우 빈 삼항을 허용하는 컴파일러가 있습니까?
Jonathan Frech

1
@OlivierDulac 확인하실 수 있습니다. 내가 아는 바에 따르면 GCC에는 다음과 같은 ?:연산자가 있습니다.a ? a : b
Chromium

75
  • main하나 이상의 정수 변수를 선언하기위한 인수 목록을 남용 하십시오.

    main(a){for(;++a<28;)putchar(95+a);}
    

    ( 프로그래밍 언어의 알파벳에 대한 답변 )

    이 솔루션은 또한 프로그램이 인수없이 호출 되면 a(일명 argc)로 시작 한다는 사실을 남용합니다 1.

  • 전역 변수를 사용하여 사물을 0으로 초기화하십시오.

    t[52],i;main(c){for(;i<52;)(c=getchar())<11?i+=26:t[i+c-97]++;
    for(i=27;--i&&t[i-1]==t[i+25];);puts(i?"false":"true");}
    

    ( 아나그램 코드 골프에 대한 답변 ! )


62

쉼표 연산자를 사용하여 중괄호를 피하면서 단일 블록에서 여러 표현식을 실행할 수 있습니다.

main(){                                                                                     

int i = 0;                                                                                  
int j = 1;                                                                                  
if(1)                                                                                       
    i=j,j+=1,printf("%d %d\n",i,j); // multiple statements are all executed                                                  
else                                                                                        
    printf("failed\n");                                                                     

}

출력 : 1 2


문 중 하나가이면 작동하지 않습니다 break.
Maxim Mikhaylov

9
@MaxLawnboy break는 진술 이므로이 답변은 표현식에 대해 이야기합니다.
NieDzejkob

59

치명적인 함수 인수 유형 선언을 피하십시오

다섯 개의 인수가 모두있는 함수를 선언하면 int인생이 좋습니다. 당신은 단순히 쓸 수 있습니다

f(a,b,c,d,e){

그러나 , 또는 d이어야 한다고 가정하십시오 . 그럼 당신은 망했어! 하나의 매개 변수 앞에 유형이 오는 경우 모두 다음과 같아야합니다.charint*

f(int a,int b,int c,int*d,int e){

하지만 기다려! 쓸모없는 캐릭터의이 비참한 폭발을 피할 수있는 방법이 있습니다. 다음과 같이 진행됩니다.

f(a,b,c,d,e) int *d; {

main명령 행 인수를 사용해야하는 경우 표준 선언 도 절약됩니다 .

main(c,v)char**v;{

2 바이트보다 짧다

main(int c,char**v){

나는 지금까지 PPCG에서 그것을 발견하지 못했기 때문에 이것을 발견하는 것에 놀랐습니다.


6
지구상에서 왜 작동합니까?
Nathaniel

30
이것은 K & R 스타일이라고하며 ANSI C보다 10 년 앞서 있습니다.
Dennis

K & R 기능과 최신 기능 (예 : '99)을 함께 사용하거나 사용하지 못할 수 있습니다. 컴파일러에 따라 다릅니다.
dmckee

5
@dmckee가 맞습니다. C99는 암시 적 int를 허용하지 않으므로 사용해야 -std=gnu99하며 이제 이식성이 없습니다. clc-speak에서는 "C"코드 자체를 작성하지 않고 "Gnu99-C"를 작성하고 있습니다. '라운드에서 우리는 대부분 그것을 무시하지만 컴파일러 특정 코드를 게시하는 경우 언급하는 것이 좋습니다. 때때로 사람들은 실제로 않습니다 다운로드하고 우리의이 프로그램을 실행합니다. :)
luser droog

@luserdroog : -std=c89gcc 또는 clang에게 이전 표준에 따라 코드를 컴파일하도록 지시하면 경고만으로 암시적인 int를 허용합니다.
Peter Cordes

37

> = 및 <= 대신에 비교 된 값이 0보다 큰 경우 정수 나누기 (/)를 사용하면 한 문자가 저장됩니다. 예를 들면 다음과 같습니다.

putchar(c/32&&126/c?c:46); //Prints the character, but if it is unprintable print "."

예를 들어> 및 ^ (일부 경우 && 또는 ||를 피하는 현명한 방법)를 사용하여 물론 축소 할 수 있습니다.

putchar(c>31^c>126?c:46);

정수 나누기 트릭은 예를 들어 문자가 저장되므로 숫자가 100보다 작은 지 여부를 결정하는 데 유용합니다.

a<100 vs 99/a

높은 우선 순위가 필요한 경우에도 좋습니다.


당신은 쓸 수 있습니다putchar(c>31&c<127?c:46);
Jin X

37

GCC와 같은 특정 컴파일러를 사용하면에 대한 기본 #include, 매개 변수 및 반환 유형 을 생략 할 수 있습니다 main.

다음은 GCC를 사용하여 경고와 함께 컴파일하는 유효한 C89 및 C99 프로그램입니다.

main(i) { printf("%d", i); }

것을 알 #includeSTDIO.H이 누락에 대한, 대한 반환 형식 main이 없습니다, 그리고에 대한 형식 선언이 i없습니다.


17
기술적으로 main은 하나가 아닌 0 또는 2 개의 매개 변수를 허용하므로 표준에 따라 유효하지 않습니다. 그 누구도 코드 골프에 관심이 없습니다.
Konrad Borowski

printf()프로토 타입없이 호출 (또는 모든 가변 함수)하면 정의되지 않은 동작이 발생 합니다. GCC는 기본적으로 표준 C를 컴파일하지 않습니다. C89 모드 ( gcc -ansi -pedantic) 또는 C99 모드 ( gcc -std=c99 -pedantic) 에서 gcc를 호출 하면 적어도 후자의 경우 상당히 많은 불만이 발생합니다.
Nisse Engström

@ NisseEngström : 메인 스트림 C 구현에 대한 호출 규칙은 프로토 타입없이 다양한 함수를 호출하는 것이 안전합니다. 따라서 대부분의 C 구현은 동작을 정의합니다.
Peter Cordes 2016 년

29

삼항 조건 연산자는 ?:종종 단순한를위한에서 스탠드로 사용할 수 있습니다 if- else상당한 비용 절감에서 문.

c ++와 달리 연산자 는 공식적으로 lvalue를 산출하지 않지만 일부 컴파일러 (특히 gcc)를 사용하면 얻을 수 없으므로 좋은 보너스입니다.


추가 : if 만 필요하지만 다른 것은 필요하지 않으면 삼항은 여전히 ​​유용 할 수 있습니다.
Casey

9
&&그리고 ||또한 사용할 수 있습니다 if(x==3)f()귀하의 제안으로되고 x==3?f():0, 추가로 개선 될 수있다 x==3&&f(). 그러나 연산자 우선 순위에주의하십시오- f()로 대체 y=1하면 &&솔루션에 추가 괄호 세트가 필요합니다.
우고 렌

1
나는 gcc ?:가 lvalue를 산출 한다는 것을 결코 깨닫지 못했다 . 프로덕션 코드에서 사용할 수 있습니까? lol
Jeff Burdges

4
@ugoren : x==3&&f()더 골프를하실 수 있습니다x^3||f()
fgrieu

@fgrieu, 그렇습니다. 그러나 여기서 정확히 주제는 아닙니다 ( 이 답변이 제안합니다).
ugoren

27

http://graphics.stanford.edu/~seander/bithacks.html

조금 좋다.

~-x = x - 1
-~x = x + 1

그러나 우선 순위가 다르고 ++ 및-와 같이 x를 변경하지 마십시오. 또한 특정 상황에서 사용할 수 있습니다. ~ 9는 -10보다 짧습니다.

if(!(x&y)) x | y == x ^ y == x + y
if(!(~x&y)) x ^ y == x - y

좀 더 난해하지만, 그것을 사용하는 경우가 있습니다. 단락에 신경 쓰지 않으면

x*y == x && y
if(x!=-y) x+y == x || y

또한:

if(x>0 && y>0) x/y == x>=y   

5
마지막 팁 ( (x/y) == (x>=y))이 정말 유용합니다.
ugoren

24

람다 사용 (휴대 불가)

대신에

f(int*a,int*b){return*a>*b?1:-1;}
...
qsort(a,b,4,f);

또는 (gcc 만 해당)

qsort(a,b,4,({int L(int*a,int*b){a=*a>*b?1:-1;}L;}));

또는 (블록을 ​​지원하는 llvm)

qsort_b(a,b,4,^(const void*a,const void*b){return*(int*)a>*(int*)b?1:-1;});

같은 것을 시도하십시오

qsort(a,b,4,"\x8b\7+\6\xc3");

인용 된 문자열에는 "lambda"기능의 기계 언어 명령어가 포함됩니다 (모든 플랫폼 ABI 요구 사항을 준수 함).

이것은 문자열 상수가 실행 가능한 것으로 표시되는 환경에서 작동합니다. 기본적으로 이것은 Linux 및 OSX에서는 사실이지만 Windows에서는 그렇지 않습니다.

"lambda"함수를 작성하는 방법을 배우는 한 가지 어리석은 방법은 C로 함수를 작성하고, 컴파일하고, 비슷한 것으로 검사하고 objdump -D, 해당 16 진 코드를 문자열로 복사하는 것입니다. 예를 들어

int f(int*a, int*b){return *a-*b;}

... gcc -Os -c리눅스 x86_64 대상 용으로 컴파일하면

0:   8b 07                   mov    (%rdi),%eax
2:   2b 06                   sub    (%rsi),%eax
4:   c3                      retq

GNU CC goto:

이 "람다 함수"를 직접 호출 할 수 있지만 호출하는 코드가 매개 변수를 사용하지 않고 리턴되지 않는 goto경우 몇 바이트를 절약 할 수 있습니다 . 그래서 대신

((int(*)())L"ﻫ")();

또는 (환경에 아랍어 글리프가없는 경우)

((int(*)())L"\xfeeb")();

시험

goto*&L"ﻫ";

또는

goto*&L"\xfeeb";

이 예에서 eb fex86 기계 언어 for(;;);는 매개 변수를 사용하지 않고 반환하지 않는 간단한 예입니다.

goto호출 부모에게 반환되는 코드 를 작성할 수 있습니다 .

#include<stdio.h>
int f(int a){
 if(!a)return 1;
 goto*&L"\xc3c031"; // return 0;
 return 2; // never gets here
}
int main(){
 printf("f(0)=%d f(1)=%d\n",f(0),f(1));
}

위 예제 (로 Linux에서 컴파일 및 실행 가능 gcc -O)는 스택 레이아웃에 민감합니다.

편집 : 툴 체인에 따라 -zexecstack컴파일 플래그 를 사용해야 할 수도 있습니다 .

그것이 명백하지 않은 경우,이 대답은 주로 lols를 위해 작성되었습니다. 나는 이것을 읽음으로써 더 나은 또는 더 나쁜 골프 또는 불리한 심리적 결과에 대해 책임을지지 않습니다.


2
방금 표준에서 C 함수의 일부를 읽고 C 람다를 인쇄하는 스크립트 를 작성했습니다 . 당신의 대답에 언급 할 가치가있을 수 있습니다. 처음 부터이 작업을 가르쳐 줬기 때문에 알게되어 기쁩니다.
MD XF

23

포인터 대신 커서 를 사용하십시오 . brk()시작 부분을 잡고 기본 포인터 로 사용하십시오 .

char*m=brk();

그런 다음 메모리 액세스를 위해 #define을 만드십시오.

#define M [m]

M*정수에 적용 되는 접미사가 됩니다. (오래된 a [x] == x [a] 트릭입니다.)

그러나 더 있습니다! 그런 다음 매크로보다 짧은 함수에서 포인터 인수를 반환하고 반환 할 수 있습니다 (특히 'return'을 약어로 사용하는 경우).

f(x){return x M;} //implicit ints, but they work like pointers
#define f(x) (x M)

포인터에서 커서를 만들려면 기본 포인터를 빼면 ptrdiff_t가 생성되어 int로 잘리고 손실은 yer biz입니다.

char *p = sbrk(sizeof(whatever)) - m;
strcpy(m+p, "hello world");

이 기술은 대답하지 않은 람다 미적분에 대한 통역사작성하는 데 사용됩니다 .


21

변수 대신 매개 변수를 정의하십시오.

f(x){int y=x+1;...}

f(x,y){y=x+1;...}

실제로 두 번째 매개 변수를 전달할 필요는 없습니다.

또한 연산자 우선 순위를 사용하여 괄호를 저장할 수 있습니다.
예를 들어, (x+y)*2될 수 있습니다 x+y<<1.


아니면 그냥 x+y*2또 다른 문자를 저장합니다.
Braden Best

4
@ B1KMusic x+y*2은 연산자 우선 순위로 인해 동일하지 않습니다.
ugoren

맞아, 롤 x + (y * 2)입니다. 나는로 x+y<<1평가되었다고 가정 하고 예제를 고쳤 x+(y<<1)으며 *2대신 제안했습니다 . 나는 비트 시프트 연산이 예를 들어 평가되었다는 것을 몰랐다(x+y)<<2
Braden Best

20

일반적으로 EOF == -1비트 NOT 연산자를 사용하여 EOF를 확인 while(~(c=getchar()))하거나 while(c=getchar()+1)모든 위치에서 c 값을 수정하십시오.


1
C를 잘 모르지만 while(1+c=getchar())작동 하지 않습니까?
ɐɔıʇǝɥʇuʎs

6
@ 호는 또한 운영자가 ɐɔıʇǝɥʇuʎs +할당 연산자보다 우선 순위가 높기 =때문에, 1+c=getchar()동등 (1+c)=getchar()때문에있는 컴파일되지 않고, (1+c)좌변이 아니다.
ace_HongKongIndependence

19

삼항 연산자 ?:는 두 개의 분리 된 부분이 있다는 점에서 특이합니다. 이 때문에 표준 운영자 우선 순위 규칙에 약간의 허점을 제공합니다. 괄호를 피하는 데 유용 할 수 있습니다.

다음 예제를 보자.

if (t()) a = b, b = 0;  /* 15 chars */

보통 골프를 치는 방법은을 대체하는 것입니다 if함께 &&하지만, 때문에 쉼표 연산자의 낮은 우선 순위, 당신은 괄호의 추가 쌍을 필요 :

t() && (a = b, b = 0);  /* still 15 chars */

삼항 연산자의 중간 부분에는 괄호가 필요하지 않습니다.

t() ? a = b, b = 0 : 0;  /* 14 chars */

배열 첨자에도 비슷한 설명이 적용됩니다.


7
이 예에서는 b-=a=b훨씬 짧습니다. ?:트릭은 여전히 유용 -=도 낮은 우선 순위를 가지고 있기 때문이다.
ugoren

좋은 지적; 내 예는 불필요하게 복잡했습니다.
breadbox

또 다른 점은 때때로 당신이 상황을 반전 할 것입니다 :에 x>0||(y=3), x>0?0:(y=3)쓸모가 없지만, x<1?y=3:0작업을 수행합니다.
ugoren

그 소리와 GCC 모두 빈을 허용 진정한 삼항의 경우. 생략하면 해당 값이 조건의 값입니다. 예 :x>5?:y=1
Chris Uzdavinis

19

여러 번 반복되는 코드 부분은 전 처리기 대체 대상입니다.

#define R return

코드가 두 개 이상의 함수를 포함하는 경우 매우 일반적인 사용 사례입니다. 같은 다른 기름 한 키워드 while, double, switch, 및 case도 후보; 코드에서 독창적 인 것뿐만 아니라.

나는 일반적으로이 목적을 위해 대문자를 예약합니다.


1
더 짧은 교체는입니다 -DR=return. 특정 문자를 포함하면 define 주위에 작은 따옴표 나 큰 따옴표가 필요할 수 있습니다 -DP='puts("hello")'.

15

프로그램이 각 단계마다 하나씩 읽거나 쓰는 경우 항상 getchar ()putchar () 대신 readwrite 함수 를 사용하십시오 .

( stdin을 뒤집고 stdout에 배치 )

main(_){write(read(0,&_,1)&&main());}

연습 :이 기술을 사용하여 좋은 점수를 얻으 십시오 .


각 단계에서 무엇을 의미 합니까?
Casey

Casey : 프로그램이 무언가를 읽고, 작동하고, 출력을 작성한다는 의미입니다. 스트리밍 방식으로 말하면. 모든 입력을 한 번에 읽고 처리해야하는 접근 방식과 달리.
Joey

Joey도 그렇습니다. 같은 의미로 죄송합니다. 오늘까지받은 편지함을 확인하지 않았습니다.
Quixotic

8
그 스택 조작은 화려합니다.
Andrea Biondo

14

리버스 루프

가능하면 교체해보십시오.

for(int i=0;i<n;i++){...}

for(int i=n;i--;){...}

13

혹시 출력에 하나의 개행 문자가 필요하면 ( \n), 사용하지 않는 putchar(10), 사용 puts("").


12

반환 값을 0으로 만듭니다. 일부 함수를 호출하고 정상적인 조건에서 해당 함수가 0을 반환하면 0이 필요한 위치에 해당 함수를 배치 할 수 있습니다. 마찬가지로 뱅을 추가하면 함수가 0이 아닌 값을 반환합니다. 결국, 어떤 경우에도 코드 골프에서 적절한 오류 처리를 수행하지 않습니까?

예 :

close(fd);foo=0;   →  foo=close(fd);    /* saves two bytes */
putchar(c);bar=0;  →  bar=!putchar(c);  /* saves one byte  */

12

반환 대신 할당하십시오.

이것은 실제로 표준 C는 아니지만 내가 아는 모든 컴파일러 및 CPU에서 작동합니다.

int sqr(int a){return a*a;}

다음과 같은 효과가 있습니다.

int sqr(int a){a*=a;}

첫 번째 인수는 반환 값과 동일한 CPU 레지스터에 저장되기 때문입니다.

참고 : 한 의견에서 언급 한 바와 같이, 이것은 정의되지 않은 동작이며 모든 작업에서 작동하지 않을 수도 있습니다. 그리고 모든 컴파일러 최적화는 그냥 건너 뜁니다.

X- 매크로

또 다른 유용한 기능 : X-Macros는 변수 목록이 있고 모든 변수를 포함하는 작업을 수행해야 할 때 도움이 될 수 있습니다.

https://ko.wikipedia.org/wiki/X_Macro


3
나는 이것을 인용하고 수정했다. 이것은 단순히 사실이 아니다. 곱셈과 나눗셈 및 최적화가 해제 된 경우에만 작동합니다. 두 작업 모두 결과를 eax (일반 반환 레지스터)에 넣기 때문입니다. 매개 변수는 스택 또는 ecx 또는 edx에 저장됩니다. 직접 해보십시오.
Gaspa79

3
당신은 맞습니다, 그것은 정의되지 않은 행동이며, 컴파일러와 아키텍처에 달려 있습니다. 나는 일반적 으로이 트릭을 사용하여 답변을 게시하기 전에 x86 및 armv7에서 gcc를 확인합니다. 물론 최적화를 활성화하면 모든 스마트 컴파일러는 불필요한 곱셈을 삭제합니다.
GB

3
나는 GCC와 함께이 작업을 보았지만 다른 사람들에게는 그렇지 않았다
Albert Renshaw

1
@ Gaspa79 : gcc with는 -O0항상 반환 값 레지스터의 표현식을 평가하도록 선택합니다. 적어도 x86, ARM 및 MIPS를 살펴 보았으며 ( gcc.godbolt.org ) gcc는에서 그렇게하지 않는 것 같습니다 -O0. 당신이 활용하지만 기억 당신이 프로그래밍하는 언어 gcc -O0, 하지 C를 하지 C로, 당신은 그에 따라 답을 레이블한다 . -O0디버그 모드 이외의 최적화 수준에서는 실패하며 clang IIRC에서는 작동하지 않습니다.
Peter Cordes 2016 년

11
  1. 배열의 첫 번째 요소에 액세스하는 *a대신 사용하십시오 a[0].

  2. 관계 연산자 ( !=, >등)는 0또는을 제공 1합니다. 조건이 참인지 거짓인지에 따라 서로 다른 오프셋을 제공하는 산술 연산자로 이것을 사용하여 a[1+2*(i<3)]액세스 할 a[1]경우 i >= 3a[3]그렇지 않은 경우.


11
a[i<3?3:1]보다 짧은 두 문자 a[1+2*(i<3)]입니다.
Reto Koradi

10

IOCCC 자료실 (국제 난독 화 C 코드 경연 대회)을 살펴볼 수 있습니다.

주목할만한 트릭 중 하나는 확장에 불균형 괄호 / 괄호가있는 매크로를 #define하는 것입니다.

#define P printf(

16
일치하지 않는 괄호는 그 자체로 가치가 없습니다. 요점은 가능한 한 많은 반복 패턴을 정의하는 것입니다. 으로 더 나아가고 싶을 수도 있습니다 #define P;printf(.
ugoren

이것은 바이트 수를 어떻게 단축합니까? 아마도 예를 제공 할 수 있습니까?
Cyoce

2
@Cyoce 예를 들어이 답변을 참조하십시오 .
Jonathan Frech

8

for(int i=0;i<n;i++){a(i);b(i);} 몇 가지 방법으로 더 짧게 만들 수 있습니다.

for(int i=0;i<n;){a(i);b(i++);}루프 ++에서 마지막 i으로 이동하기위한 -1

for(int i=0;i<n;b(i++))a(i); 하나의 문장을 제외한 모든 문장을 메인 루프의 상단 및 상단 루프로 이동하여 중괄호를 제거하면 -3 더


쉼표 연산자를 사용하는 것은 경우에 따라 중괄호를 피하는 또 다른 방법입니다.
Peter Cordes 2016 년

8

기능적!

동일한 시그니처를 사용하고 단일 표현식으로 정의 된 간단한 함수로 문제를 줄일 수 있다면 #define r return, 함수를 정의하기 위해 거의 모든 상용구 보다 더 잘 수행 할 수 있습니다 .

#define D(f,...)f(x){return __VA_ARGS__;}
D(f,x+2)
D(g,4*x-4)
D(main,g(4))

프로그램 결과는 OS 또는 제어 쉘 또는 IDE로 리턴되는 상태 값입니다.

사용은 __VA_ARGS__당신이 다음에 순서 포인트를 소개하는 쉼표 연산자를 사용할 수 있도록 기능 표현식 . 이것이 필요하지 않으면 매크로가 더 짧아 질 수 있습니다.

#define D(f,b)f(x){return b;}

7
  1. scanf("%*d ");더미 입력을 읽는 데 사용 합니다. (추가 프로그램에서 입력이 의미가없는 경우) scanf("%d",&t);변수 t를 선언 해야하는 위치 보다 짧습니다 .

  2. int 배열에 문자를 저장하는 것이 문자 배열보다 훨씬 좋습니다. 예.

    s[],t;main(c){for(scanf("%*d ");~(c=getchar());s[t++]=c)putchar(s[t]);}


2
실제로, 나는 %*d골프 scanf("%[^\n]%*c",str);
에서뿐만 아니라

6

다음 대신에 문자를 인쇄 한 다음 캐리지 리턴을 인쇄하십시오.

printf("%c\n",c);

또는

putchar(c);putchar('\n'); // or its ascii value, whatever!

간단히, c를 int로 선언하고 :

puts(&c);

9
이것이 리틀 엔디안 아키텍처에 달려 있다는 것을 지적 할 가치가 있습니다. c가 빅 엔디안 int이면 캐리지 리턴을 얻습니다. (반면, c가 문자 인 경우 캐리지 리턴 대신 임의의 쓰레기를 얻을 수 있습니다.)
breadbox

@breadbox 네, 당신은 완전히 옳습니다; 방금 편집 : 마지막 발췌는 c를 int로 사용해야합니다 (종종 선언하기 쉽습니다).
moala

합니까 puts(&c)정말 작동? 반드시 null로 끝나는 것은 아닙니다.
Esolanging Fruit

1
@EsolangingFruit 32 비트 int를 가진 little-endian에서 int 0 ≤ c <256 은 바이트 시퀀스 c 0 0 0으로 저장됩니다 . 의 주소 인터프리터 때 C 등을 char *문자 : 우리는 단일 문자열 참조 C , null 바이트 다음을.
Dennis

6

를 사용 asprintf()하면 명시 적으로 할당하고 문자열 길이를 측정 할 수 있습니다 char*! 이것은 코드 골프에 너무 유용하지는 않지만 char 배열로 일상적인 작업을 용이하게합니다. 21 세기 C 에는 더 좋은 조언이 있습니다.

사용 예 :

#define _GNU_SOURCE
#include <stdio.h>

int main(int argc, char** argv) {
  char* foo;
  asprintf(&foo, "%s", argv[1]);
  printf("%s",foo);
}

6

import 당신이해야한다면

첫 번째 답변 에서 언급했듯이 일부 컴파일러 (특히 GCC 및 clang)를 사용하면 #include표준 라이브러리 기능 을 생략 할 수 있습니다 .

를 제거 할 수 없더라도 피할#include 수있는 다른 방법 이있을 수 있지만 항상 실용적이거나 특히 골프는 아닙니다.

나머지 경우 에는 바이트를 저장하는 #import<header file>대신 사용할 수 있습니다 #include<header file>. 이것은 GNU 확장이며 더 이상 사용되지 않는 것으로 간주되지만 적어도 gcc 4.8, gcc 5.1 및 clang 3.7에서 작동합니다.


6

cpow()대신 사용해보십시오cos()

대신에

double y=cos(M_PI*2*x);

같은 것을 시도하십시오

double y=cpow(-1,x*2);

여기에는 오일러의 공식 , 약간 복잡한 분석 및 복소수를 두 배로 할당하면 실제 부분이 생성된다는 관찰 결과가 사용됩니다 (Variadic 함수 호출 및 기타 미묘함에주의).

\ cos 2 \ pi x + j \ sin 2 \ pi x = e ^ {j2 \ pi x} = e ^ {j \ pi 2x} = (-1) ^ {2x}

이 유형의 트릭을 사용하여

double y=cpow(-1,x/2);

으로

double y=cpow(1i,x);

때문에 (-1) ^ \ frac {x} {2} = j ^ {\ frac {2x} {2}} = j ^ x


5

여기에 내가 사용했던 몇 가지 팁이 있습니다. 나는 타인에게 뻔뻔스럽게 도난 당 했으므로 나 외에는 누구에게도 신용하지 않습니다.

할당을 함수 호출과 결합

이 대신에 :

r = /* Some random expression */
printf("%d", r);

이 작업을 수행:

printf("%d", r = /* Some random expression */);

여러 변수를 함께 초기화 (가능한 경우)

이 대신에 :

for(i=0,j=0;...;...){ /* ... */ }

이 작업을 수행:

for(i=j=0;...;...){ /* ... */ }

0/0이 아닌 값 축소

이것은 내가 누군가 여기에서 가져온 깔끔한 트릭입니다 (누군가를 기억하지 마십시오. 죄송합니다). 정수 값이 있고이를 1 또는 0으로 축소해야 !!할 때 쉽게 사용할 수 있습니다. 이것은 때때로 다른 대안에 유리하다 ?:.

이 상황을 보자 :

n=2*n+isupper(s[j])?1:0; /* 24 */

대신 이것을 할 수 있습니다 :

n=n*2+!!isupper(s[j]); /* 22 */

또 다른 예:

r=R+(memcmp(b+6,"---",3)?R:0); /* 30 */

다음과 같이 다시 작성할 수 있습니다.

r=R+R*!!memcmp(b+6,"---",3)); /* 29 */

1
아마R*-~!!mxxxx
l4m2

5

기본적인 논리적 평등을 알면 몇 바이트를 절약 할 수 있습니다. 예를 들어, if (!(a&&b)){}DeMorgan 's law 대신에 시도하십시오 if (!a||!b){}. 비트 함수에도 동일하게 적용됩니다 . ~(a|b)do 대신 ~a&~b.


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