답변:
비트 XOR을 사용하여 정수 사이의 불평등을 확인하십시오.
if(a^b)대신 if(a!=b)1자를 저장합니다.
a-b같은 효과를줍니다.
a*b대신 사용할 수 있습니다 a&&b(우선 순위가 다르거 나 나쁘거나 나쁘지 않을 수 있음). 만약 당신이 / = -b를 알고 있다면 (예를 들어, 부호가 없다) a||b==a+b
?:(대신 경우의) : exemple를 위해 뭔가를 할 수있는 경우의 differents : a^b?_diff_:;
?:연산자가 있습니다.a ? a : b
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");}
( 아나그램 코드 골프에 대한 답변 ! )
쉼표 연산자를 사용하여 중괄호를 피하면서 단일 블록에서 여러 표현식을 실행할 수 있습니다.
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.
break는 진술 이므로이 답변은 표현식에 대해 이야기합니다.
다섯 개의 인수가 모두있는 함수를 선언하면 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에서 그것을 발견하지 못했기 때문에 이것을 발견하는 것에 놀랐습니다.
-std=gnu99하며 이제 이식성이 없습니다. clc-speak에서는 "C"코드 자체를 작성하지 않고 "Gnu99-C"를 작성하고 있습니다. '라운드에서 우리는 대부분 그것을 무시하지만 컴파일러 특정 코드를 게시하는 경우 언급하는 것이 좋습니다. 때때로 사람들은 실제로 않습니다 다운로드하고 우리의이 프로그램을 실행합니다. :)
-std=c89gcc 또는 clang에게 이전 표준에 따라 코드를 컴파일하도록 지시하면 경고만으로 암시적인 int를 허용합니다.
> = 및 <= 대신에 비교 된 값이 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);
GCC와 같은 특정 컴파일러를 사용하면에 대한 기본 #include, 매개 변수 및 반환 유형 을 생략 할 수 있습니다 main.
다음은 GCC를 사용하여 경고와 함께 컴파일하는 유효한 C89 및 C99 프로그램입니다.
main(i) { printf("%d", i); }
것을 알 #includeSTDIO.H이 누락에 대한, 대한 반환 형식 main이 없습니다, 그리고에 대한 형식 선언이 i없습니다.
printf()프로토 타입없이 호출 (또는 모든 가변 함수)하면 정의되지 않은 동작이 발생 합니다. GCC는 기본적으로 표준 C를 컴파일하지 않습니다. C89 모드 ( gcc -ansi -pedantic) 또는 C99 모드 ( gcc -std=c99 -pedantic) 에서 gcc를 호출 하면 적어도 후자의 경우 상당히 많은 불만이 발생합니다.
삼항 조건 연산자는 ?:종종 단순한를위한에서 스탠드로 사용할 수 있습니다 if- else상당한 비용 절감에서 문.
c ++와 달리 연산자 는 공식적으로 lvalue를 산출하지 않지만 일부 컴파일러 (특히 gcc)를 사용하면 얻을 수 없으므로 좋은 보너스입니다.
&&그리고 ||또한 사용할 수 있습니다 if(x==3)f()귀하의 제안으로되고 x==3?f():0, 추가로 개선 될 수있다 x==3&&f(). 그러나 연산자 우선 순위에주의하십시오- f()로 대체 y=1하면 &&솔루션에 추가 괄호 세트가 필요합니다.
?:가 lvalue를 산출 한다는 것을 결코 깨닫지 못했다 . 프로덕션 코드에서 사용할 수 있습니까? lol
x==3&&f()더 골프를하실 수 있습니다x^3||f()
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
(x/y) == (x>=y))이 정말 유용합니다.
대신에
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
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를 위해 작성되었습니다. 나는 이것을 읽음으로써 더 나은 또는 더 나쁜 골프 또는 불리한 심리적 결과에 대해 책임을지지 않습니다.
포인터 대신 커서 를 사용하십시오 . 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");
이 기술은 대답하지 않은 람다 미적분에 대한 통역사 를 작성하는 데 사용됩니다 .
변수 대신 매개 변수를 정의하십시오.
f(x){int y=x+1;...}
f(x,y){y=x+1;...}
실제로 두 번째 매개 변수를 전달할 필요는 없습니다.
또한 연산자 우선 순위를 사용하여 괄호를 저장할 수 있습니다.
예를 들어, (x+y)*2될 수 있습니다 x+y<<1.
x+y*2또 다른 문자를 저장합니다.
x+y*2은 연산자 우선 순위로 인해 동일하지 않습니다.
x+y<<1평가되었다고 가정 하고 예제를 고쳤 x+(y<<1)으며 *2대신 제안했습니다 . 나는 비트 시프트 연산이 예를 들어 평가되었다는 것을 몰랐다(x+y)<<2
일반적으로 EOF == -1비트 NOT 연산자를 사용하여 EOF를 확인 while(~(c=getchar()))하거나 while(c=getchar()+1)모든 위치에서 c 값을 수정하십시오.
while(1+c=getchar())작동 하지 않습니까?
+할당 연산자보다 우선 순위가 높기 =때문에, 1+c=getchar()동등 (1+c)=getchar()때문에있는 컴파일되지 않고, (1+c)좌변이 아니다.
삼항 연산자 ?:는 두 개의 분리 된 부분이 있다는 점에서 특이합니다. 이 때문에 표준 운영자 우선 순위 규칙에 약간의 허점을 제공합니다. 괄호를 피하는 데 유용 할 수 있습니다.
다음 예제를 보자.
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 */
배열 첨자에도 비슷한 설명이 적용됩니다.
b-=a=b훨씬 짧습니다. ?:트릭은 여전히 유용 -=도 낮은 우선 순위를 가지고 있기 때문이다.
x>0||(y=3), x>0?0:(y=3)쓸모가 없지만, x<1?y=3:0작업을 수행합니다.
x>5?:y=1
프로그램이 각 단계마다 하나씩 읽거나 쓰는 경우 항상 getchar () 및 putchar () 대신 read 및 write 함수 를 사용하십시오 .
예 ( stdin을 뒤집고 stdout에 배치 )
main(_){write(read(0,&_,1)&&main());}
연습 :이 기술을 사용하여 좋은 점수를 얻으 십시오 .
혹시 출력에 하나의 개행 문자가 필요하면 ( \n), 사용하지 않는 putchar(10), 사용 puts("").
이것은 실제로 표준 C는 아니지만 내가 아는 모든 컴파일러 및 CPU에서 작동합니다.
int sqr(int a){return a*a;}
다음과 같은 효과가 있습니다.
int sqr(int a){a*=a;}
첫 번째 인수는 반환 값과 동일한 CPU 레지스터에 저장되기 때문입니다.
참고 : 한 의견에서 언급 한 바와 같이, 이것은 정의되지 않은 동작이며 모든 작업에서 작동하지 않을 수도 있습니다. 그리고 모든 컴파일러 최적화는 그냥 건너 뜁니다.
또 다른 유용한 기능 : X-Macros는 변수 목록이 있고 모든 변수를 포함하는 작업을 수행해야 할 때 도움이 될 수 있습니다.
-O0항상 반환 값 레지스터의 표현식을 평가하도록 선택합니다. 적어도 x86, ARM 및 MIPS를 살펴 보았으며 ( gcc.godbolt.org ) gcc는에서 그렇게하지 않는 것 같습니다 -O0. 당신이 활용하지만 기억 당신이 프로그래밍하는 언어 gcc -O0, 하지 C를 하지 C로, 당신은 그에 따라 답을 레이블한다 . -O0디버그 모드 이외의 최적화 수준에서는 실패하며 clang IIRC에서는 작동하지 않습니다.
배열의 첫 번째 요소에 액세스하는 *a대신 사용하십시오 a[0].
관계 연산자 ( !=, >등)는 0또는을 제공 1합니다. 조건이 참인지 거짓인지에 따라 서로 다른 오프셋을 제공하는 산술 연산자로 이것을 사용하여 a[1+2*(i<3)]액세스 할 a[1]경우 i >= 3와 a[3]그렇지 않은 경우.
a[i<3?3:1]보다 짧은 두 문자 a[1+2*(i<3)]입니다.
IOCCC 자료실 (국제 난독 화 C 코드 경연 대회)을 살펴볼 수 있습니다.
주목할만한 트릭 중 하나는 확장에 불균형 괄호 / 괄호가있는 매크로를 #define하는 것입니다.
#define P printf(
#define P;printf(.
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 더
동일한 시그니처를 사용하고 단일 표현식으로 정의 된 간단한 함수로 문제를 줄일 수 있다면 #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;}
다음 대신에 문자를 인쇄 한 다음 캐리지 리턴을 인쇄하십시오.
printf("%c\n",c);
또는
putchar(c);putchar('\n'); // or its ascii value, whatever!
간단히, c를 int로 선언하고 :
puts(&c);
puts(&c)정말 작동? 반드시 null로 끝나는 것은 아닙니다.
char *문자 : 우리는 단일 문자열 참조 C , null 바이트 다음을.
를 사용 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);
}
import 당신이해야한다면첫 번째 답변 에서 언급했듯이 일부 컴파일러 (특히 GCC 및 clang)를 사용하면 #include표준 라이브러리 기능 을 생략 할 수 있습니다 .
를 제거 할 수 없더라도 피할#include 수있는 다른 방법 이있을 수 있지만 항상 실용적이거나 특히 골프는 아닙니다.
나머지 경우 에는 바이트를 저장하는 #import<header file>대신 사용할 수 있습니다 #include<header file>. 이것은 GNU 확장이며 더 이상 사용되지 않는 것으로 간주되지만 적어도 gcc 4.8, gcc 5.1 및 clang 3.7에서 작동합니다.
여기에 내가 사용했던 몇 가지 팁이 있습니다. 나는 타인에게 뻔뻔스럽게 도난 당 했으므로 나 외에는 누구에게도 신용하지 않습니다.
할당을 함수 호출과 결합
이 대신에 :
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 */
R*-~!!mxxxx
기본적인 논리적 평등을 알면 몇 바이트를 절약 할 수 있습니다. 예를 들어, if (!(a&&b)){}DeMorgan 's law 대신에 시도하십시오 if (!a||!b){}. 비트 함수에도 동일하게 적용됩니다 . ~(a|b)do 대신 ~a&~b.