가장 좋아하는 C 프로그래밍 트릭은 무엇입니까? [닫은]
예를 들어, 나는 최근 리눅스 커널에서 이것을 발견했다.
/ * 조건이 true 인 경우 컴파일 오류를 발생시킵니다 * / #define BUILD_BUG_ON (condition) ((void) sizeof (char [1-2 * !! (condition)]))
따라서 코드에서 8 바이트 크기의 배수와 같은 일부 구조가있는 경우 하드웨어 제약으로 인해 다음을 수행 할 수 있습니다.
BUILD_BUG_ON (((sizeof (struct mystruct) % 8)! = 0);
struct mystruct의 크기가 8의 배수가 아닌 한 컴파일되지 않으며 8의 배수이면 런타임 코드가 전혀 생성되지 않습니다.
내가 아는 또 다른 트릭은 단일 헤더 파일이 한 모듈에서 변수를 선언하고 초기화하는 동안 해당 모듈을 사용하는 다른 모듈에서는 externs로 선언 할 수있는 "Graphics Gems"책에서 나온 것입니다.
#ifdef DEFINE_MYHEADER_GLOBALS #define GLOBAL INIT (x, y) 정의 (x) = (y) #그밖에 #define GLOBAL extern INIT 정의 (x, y) #endif GLOBAL int INIT (x, 0); GLOBAL int somefunc (int a, int b);
이를 통해 x와 somefunc를 정의하는 코드는 다음을 수행합니다.
#DEFINE_MYHEADER_GLOBALS 정의 #include "the_above_header_file.h"
x와 somefunc ()를 사용하는 코드는 다음과 같습니다.
#include "the_above_header_file.h"
따라서 필요한 전역 및 함수 프로토 타입 인스턴스와 해당 extern 선언을 모두 선언하는 하나의 헤더 파일을 얻습니다.
그렇다면 그 라인에서 가장 좋아하는 C 프로그래밍 트릭은 무엇입니까?
C99는 익명 배열을 사용하여 정말 멋진 것들을 제공합니다.
무의미한 변수 제거
{
int yes=1;
setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
}
된다
setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, (int[]){1}, sizeof(int));
가변 인수 인수 전달
void func(type* values) {
while(*values) {
x = *values++;
/* do whatever with x */
}
}
func((type[]){val1,val2,val3,val4,0});
정적 링크리스트
int main() {
struct llist { int a; struct llist* next;};
#define cons(x,y) (struct llist[]){{x,y}}
struct llist *list=cons(1, cons(2, cons(3, cons(4, NULL))));
struct llist *p = list;
while(p != 0) {
printf("%d\n", p->a);
p = p->next;
}
}
내가 생각하지 못한 다른 멋진 기술이 많이 있다고 확신합니다.
Quake 2 소스 코드를 읽는 동안 나는 다음과 같은 것을 생각해 냈습니다.
double normals[][] = {
#include "normals.txt"
};
(더 많거나 적은, 지금 확인하기 편리한 코드가 없습니다).
그 이후로, 전 처리기의 창조적 인 사용의 새로운 세계가 내 눈앞에서 열렸다. 더 이상 헤더 만 포함하지 않지만 이제는 전체 코드 덩어리를 재사용 할 수 있습니다.
존 카맥 감사합니다! xD
= {0};
memset을 호출하지 않고도 구조를 초기화 하는 것을 좋아 합니다.
struct something X = {0};
이것은 구조체 (또는 배열)의 모든 멤버를 0으로 초기화합니다 (그러나 패딩 바이트는 아님)-0을 초기화 해야하는 경우 memset을 사용하십시오).
그러나 동적으로 할당 된 대규모 구조에는 이와 관련하여 몇 가지 문제 가 있음을 알고 있어야합니다 .
우리가 C 트릭에 대해 이야기하고 있다면, 내가 가장 좋아하는 것은 루프 언 롤링을위한 더프의 장치 여야합니다 ! 나는 실제로 분노에서 그것을 사용할 수있는 올바른 기회를 기다리고 있습니다 ...
사용 __FILE__
및 __LINE__
디버깅
#define WHERE fprintf(stderr,"[LOG]%s:%d\n",__FILE__,__LINE__);
C99에서
typedef struct{
int value;
int otherValue;
} s;
s test = {.value = 15, .otherValue = 16};
/* or */
int a[100] = {1,2,[50]=3,4,5,[23]=6,7};
일단 내 친구와 나는 다시 정의하기가 까다로운 스택 손상 버그를 발견했습니다.
다음과 같은 것 :
#define return DoSomeStackCheckStuff, return
나는 동적 크기의 객체를 갖는 "struct hack"을 좋아한다. 이 사이트에서도 설명 이 잘되어 있습니다 (스트럭처의 마지막 멤버로 "str []"를 쓸 수있는 C99 버전을 참조하십시오). 다음과 같이 문자열 "object"를 만들 수 있습니다.
struct X {
int len;
char str[1];
};
int n = strlen("hello world");
struct X *string = malloc(sizeof(struct X) + n);
strcpy(string->str, "hello world");
string->len = n;
여기에서는 int (len의 크기)와 "hello world"의 길이, 1을 더한 힙에 X 유형의 구조를 할당했습니다 ( 1 은 str 의 크기가 sizeof (X)에 포함되므로).
일반적으로 동일한 블록에서 일부 가변 길이 데이터 바로 앞에 "헤더"를 사용하려는 경우에 유용합니다.
클래스를 에뮬레이트하여 C를 사용한 객체 지향 코드
구조체와 해당 구조체에 대한 포인터를 첫 번째 매개 변수로 사용하는 함수 집합을 만들기 만하면됩니다.
대신에
printf("counter=%d\n",counter);
사용하다
#define print_dec(var) printf("%s=%d\n",#var,var);
print_dec(counter);
어리석은 매크로 트릭을 사용하여 레코드 정의를보다 쉽게 관리 할 수 있습니다.
#define COLUMNS(S,E) [(E) - (S) + 1]
typedef struct
{
char studentNumber COLUMNS( 1, 9);
char firstName COLUMNS(10, 30);
char lastName COLUMNS(31, 51);
} StudentRecord;
선언 된 것을 제외한 모든 모듈에서 읽기 전용 인 변수를 작성하려면 다음을 수행하십시오.
// Header1.h:
#ifndef SOURCE1_C
extern const int MyVar;
#endif
// Source1.c:
#define SOURCE1_C
#include Header1.h // MyVar isn't seen in the header
int MyVar; // Declared in this file, and is writeable
// Source2.c
#include Header1.h // MyVar is seen as a constant, declared elsewhere
비트 시프트는 31의 시프트 량 (32 비트 정수)까지만 정의됩니다.
더 높은 쉬프트 값으로 작동해야하는 계산 된 쉬프트를 원한다면 어떻게해야합니까? Theora vide-codec의 작동 방식은 다음과 같습니다.
unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
return (a>>(v>>1))>>((v+1)>>1);
}
또는 훨씬 더 읽기 쉽다 :
unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
unsigned int halfshift = v>>1;
unsigned int otherhalf = (v+1)>>1;
return (a >> halfshift) >> otherhalf;
}
위와 같은 방법으로 작업을 수행하는 것은 다음과 같이 분기를 사용하는 것보다 훨씬 빠릅니다.
unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
if (v<=31)
return a>>v;
else
return 0;
}
유한 상태 머신을 구현하기위한 함수에 대한 포인터의 배열 선언.
int (* fsm[])(void) = { ... }
가장 좋은 장점은 각 자극 / 상태가 모든 코드 경로를 확인하도록하는 것이 간단하다는 것입니다.
임베디드 시스템에서는 종종 ISR을 매핑하여 그러한 테이블을 가리키고 필요에 따라 ISR 외부로 벡터를 다시 만듭니다.
또 다른 좋은 전 처리기 "트릭"은 "#"문자를 사용하여 디버깅 표현식을 인쇄하는 것입니다. 예를 들면 다음과 같습니다.
#define MY_ASSERT(cond) \
do { \
if( !(cond) ) { \
printf("MY_ASSERT(%s) failed\n", #cond); \
exit(-1); \
} \
} while( 0 )
편집 : 아래 코드는 C ++에서만 작동합니다. smcameron과 Evan Teran에게 감사합니다.
예, 컴파일 시간 주장은 항상 훌륭합니다. 다음과 같이 쓸 수도 있습니다 :
#define COMPILE_ASSERT(cond)\
typedef char __compile_time_assert[ (cond) ? 0 : -1]
나는 그것을 사용하지 않았기 때문에 실제로 그것을 좋아하는 트릭이라고 부르지 않을 것이지만, Duff 's Device에 대한 언급은 C에서 Coroutines를 구현하는 것에 대한 이 기사를 상기시켜주었습니다 . 그것은 항상 저를 방해합니다. 시간이 좀있어
#if TESTMODE == 1
debug=1;
while(0); // Get attention
#endif
while (0); 프로그램에는 영향을 미치지 않지만 컴파일러는 "이 작업은 수행하지 않습니다"라는 경고를 표시합니다. 문제가되는 행을보고주의를 기울여야 할 실제 이유를 확인할 수 있습니다.
나는 xor 핵의 팬입니다.
세 번째 임시 포인터없이 2 개의 포인터를 교체합니다.
int * a;
int * b;
a ^= b;
b ^= a;
a ^= b;
또는 하나의 포인터로 xor 연결 목록을 정말 좋아합니다. (http://en.wikipedia.org/wiki/XOR_linked_list)
링크 된 목록의 각 노드는 이전 노드의 Xor와 다음 노드입니다. 앞으로 이동하기 위해 노드의 주소는 다음과 같은 방식으로 발견됩니다.
LLNode * first = head;
LLNode * second = first.linked_nodes;
LLNode * third = second.linked_nodes ^ first;
LLNode * fourth = third.linked_nodes ^ second;
기타
또는 뒤로 이동하려면
LLNode * last = tail;
LLNode * second_to_last = last.linked_nodes;
LLNode * third_to_last = second_to_last.linked_nodes ^ last;
LLNode * fourth_to_last = third_to_last.linked_nodes ^ second_to_last;
기타
별로 유용하지는 않지만 (임의의 노드에서 순회를 시작할 수 없음) 매우 멋집니다.
이것은 '발로 몸을 쏠 수있는 충분한 밧줄'책에서 나온 것입니다.
헤더에서 선언
#ifndef RELEASE
# define D(x) do { x; } while (0)
#else
# define D(x)
#endif
코드 장소 테스트 문장에서 예를 들면 다음과 같습니다.
D(printf("Test statement\n"));
do / while은 매크로의 내용이 여러 명령문으로 확장되는 경우 도움이됩니다.
컴파일러에 대한 '-D RELEASE'플래그가 사용되지 않은 경우에만 명령문이 인쇄됩니다.
그런 다음 예를 들어. 플래그를 makefile 등에 전달하십시오.
이것이 Windows에서 어떻게 작동하는지 확실하지 않지만 * nix에서는 잘 작동합니다.
Rusty는 실제로 ccan 에서 전체 빌드 조건 세트를 생성 했습니다. 빌드 assert 모듈을 확인하십시오.
#include <stddef.h>
#include <ccan/build_assert/build_assert.h>
struct foo {
char string[5];
int x;
};
char *foo_string(struct foo *foo)
{
// This trick requires that the string be first in the structure
BUILD_ASSERT(offsetof(struct foo, string) == 0);
return (char *)foo;
}
실제 헤더에는 다른 유용한 매크로가 많이 있으며 제자리에 놓기가 쉽습니다.
나는 대부분 인라인 함수를 사용하여 어두운면 (및 전 처리기 남용)의 견인에 저항하기 위해 최선을 다하지만, 나는 당신이 묘사 한 것과 같은 영리하고 유용한 매크로를 즐깁니다.
이런 종류의 것들에 대한 두 가지 좋은 소스 북은 The Practice of Programming and Writing Solid Code 입니다. 그들 중 하나 (어떤 것을 기억하지 못합니까)는 말합니다 : enum은 컴파일러가 검사하기 때문에 가능한 곳을 #define보다 선호합니다.
C에만 국한된 것은 아니지만 항상 XOR 연산자를 좋아했습니다. 그것이 할 수있는 멋진 일은 "임시 값없이 교체"입니다.
int a = 1;
int b = 2;
printf("a = %d, b = %d\n", a, b);
a ^= b;
b ^= a;
a ^= b;
printf("a = %d, b = %d\n", a, b);
결과:
a = 1, b = 2
a = 2, b = 1
"C의 숨겨진 기능" 질문을 참조하십시오 .
container_of
예를 들어 목록에서 사용되는 개념이 마음 에 듭니다. 기본적으로 목록에 포함될 각 구조에 대해 next
및 last
필드 를 지정할 필요는 없습니다 . 대신 목록 구조 헤더를 실제 연결된 항목에 추가합니다.
include/linux/list.h
실제 사례를 살펴보십시오 .
userdata 포인터를 사용하는 것이 매우 깔끔 하다고 생각합니다 . 요즘 유행하는 패션. C 기능은 아니지만 C에서 사용하기 쉽습니다.
사전 컴파일러가 코드를 생성 하도록 X-Macros 를 사용 합니다. 한 곳에서 오류 값과 관련 오류 문자열을 정의하는 데 특히 유용하지만 그 이상을 넘어 설 수 있습니다.
우리의 코드베이스는
#ifdef DEBUG
#define my_malloc(amt) my_malloc_debug(amt, __FILE__, __LINE__)
void * my_malloc_debug(int amt, char* file, int line)
#else
void * my_malloc(int amt)
#endif
{
//remember file and line no. for this malloc in debug mode
}
which allows for the tracking of memory leaks in debug mode. I always thought this was cool.
Fun with macros:
#define SOME_ENUMS(F) \
F(ZERO, zero) \
F(ONE, one) \
F(TWO, two)
/* Now define the constant values. See how succinct this is. */
enum Constants {
#define DEFINE_ENUM(A, B) A,
SOME_ENUMS(DEFINE_ENUMS)
#undef DEFINE_ENUM
};
/* Now a function to return the name of an enum: */
const char *ToString(int c) {
switch (c) {
default: return NULL; /* Or whatever. */
#define CASE_MACRO(A, B) case A: return #b;
SOME_ENUMS(CASE_MACRO)
#undef CASE_MACRO
}
}
Here is an example how to make C code completly unaware about what is actually used of HW for running the app. The main.c does the setup and then the free layer can be implemented on any compiler/arch. I think it is quite neat for abstracting C code a bit, so it does not get to be to spesific.
Adding a complete compilable example here.
/* free.h */
#ifndef _FREE_H_
#define _FREE_H_
#include <stdio.h>
#include <string.h>
typedef unsigned char ubyte;
typedef void (*F_ParameterlessFunction)() ;
typedef void (*F_CommandFunction)(ubyte byte) ;
void F_SetupLowerLayer (
F_ParameterlessFunction initRequest,
F_CommandFunction sending_command,
F_CommandFunction *receiving_command);
#endif
/* free.c */
static F_ParameterlessFunction Init_Lower_Layer = NULL;
static F_CommandFunction Send_Command = NULL;
static ubyte init = 0;
void recieve_value(ubyte my_input)
{
if(init == 0)
{
Init_Lower_Layer();
init = 1;
}
printf("Receiving 0x%02x\n",my_input);
Send_Command(++my_input);
}
void F_SetupLowerLayer (
F_ParameterlessFunction initRequest,
F_CommandFunction sending_command,
F_CommandFunction *receiving_command)
{
Init_Lower_Layer = initRequest;
Send_Command = sending_command;
*receiving_command = &recieve_value;
}
/* main.c */
int my_hw_do_init()
{
printf("Doing HW init\n");
return 0;
}
int my_hw_do_sending(ubyte send_this)
{
printf("doing HW sending 0x%02x\n",send_this);
return 0;
}
F_CommandFunction my_hw_send_to_read = NULL;
int main (void)
{
ubyte rx = 0x40;
F_SetupLowerLayer(my_hw_do_init,my_hw_do_sending,&my_hw_send_to_read);
my_hw_send_to_read(rx);
getchar();
return 0;
}
if(---------)
printf("hello");
else
printf("hi");
Fill in the blanks so that neither hello nor hi would appear in output.
ans: fclose(stdout)
참고URL : https://stackoverflow.com/questions/599365/what-is-your-favorite-c-programming-trick
'IT' 카테고리의 다른 글
오류 LNK2019 : ___tmainCRTStartup 함수에서 참조 된 해결되지 않은 외부 기호 _WinMain @ 16 (0) | 2020.06.26 |
---|---|
콘솔이 숨겨진 상태에서 C # 콘솔 응용 프로그램을 실행하는 방법 (0) | 2020.06.26 |
Android '창을 추가 할 수 없음-토큰 널이 애플리케이션 용이 아닙니다'예외 (0) | 2020.06.26 |
NOLOCK이있는 엔터티 프레임 워크 (0) | 2020.06.25 |
IntelliJ IDEA에서 클래스의 모든 부모 및 하위 클래스를 표시하는 방법은 무엇입니까? (0) | 2020.06.25 |