programing

C에서 .h 파일의 비정상적인 사용

luckcodes 2022. 8. 7. 18:20

C에서 .h 파일의 비정상적인 사용

.h- - 계 채 채 채 채 데 데 다 다 다 다 다 。

#define N 100 // filter order
float h[N] = { #include "f1.h" }; //insert coefficients of filter
float x[N];
float y[N];

short my_FIR(short sample_data)
{
  float result = 0;

  for ( int i = N - 2 ; i >= 0 ; i-- )
  {
    x[i + 1] = x[i];
    y[i + 1] = y[i];
  }

  x[0] = (float)sample_data;

  for (int k = 0; k < N; k++)
  {
    result = result + x[k]*h[k];
  }
  y[0] = result;

  return ((short)result);
}

보통 럼, 이, 이, 이, 이, 이, 이, 습, 습, 습, to, so, to, to, to, to, to, to, to, to ,float h[N] = { #include "f1.h" };★★★★★★★★★★★★★★★★★★?

프리프로세서 명령어#include는 텍스트 치환을 하고 있을 뿐입니다(GCC 의 GNU cpp 매뉴얼 참조).이것은, 코멘트나 문자열 리터럴 이외의 장소에서도 발생할 수 있습니다.

a, a.#include 나름의 가치가 있다#이 행의 첫 번째 공백이 아닌 문자로 표시됩니다. 코드를 쓰세요.

float h[N] = {
  #include "f1.h"
};

원래 질문에는 다음과 같은 내용이 없었습니다.#include그래서 코드를 잘못 입력했어요.

그것은 일반적인 관행은 아니지만, 허용되는 관행이다.이 경우, 다음 확장자를 사용하는 것이 좋습니다..h :: 용 e를 사용합니다.#include "f1.def" ★★★★★★★★★★★★★★★★★」#include "f1.data"

컴파일러에게 사전 처리된 폼을 보여 달라고 요청하십시오.GCC를 사용한 컴파일gcc -C -E -Wall yoursource.c > yoursource.i된 ""를 찾습니다.yoursource.i

저는 실제로 이러한 데이터를 소스 파일에 저장하는 것을 선호합니다. 대신 완결형 "을 을 제안합니다.h-data.c예를 들어 GNU awk(so file)와 같은 도구를 사용하여 파일을 만듭니다.h-data.c '아까보다'로 합니다.const float h[345] = {으로 with으 and and and and and로 };하는 것이 .)const float h[] 읽기 세그먼트에 (세그먼트), (세그먼트), 읽기 전용 (세그먼트)에 수 ..rodata★★★★★★★★★★★★★★★★★★★★★」 임베디드 는, ) 일이 ( 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」( 「 」 ) 。h-data.c★★★★★★★★★★★★★★★★★★★★★★★★★」

앞의 답변에서 이미 설명한 바와 같이, 이것은 일반적인 관행이 아니라 유효한 관행이 됩니다.

대체 솔루션은 다음과 같습니다.

파일 f1.h:

#ifndef F1_H
#define F1_H

#define F1_ARRAY                   \
{                                  \
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \
    10,11,12,13,14,15,16,17,18,19, \
    20,21,22,23,24,25,26,27,28,29, \
    30,31,32,33,34,35,36,37,38,39, \
    40,41,42,43,44,45,46,47,48,49, \
    50,51,52,53,54,55,56,57,58,59, \
    60,61,62,63,64,65,66,67,68,69, \
    70,71,72,73,74,75,76,77,78,79, \
    80,81,82,83,84,85,86,87,88,89, \
    90,91,92,93,94,95,96,97,98,99  \
}

// Values above used as an example

#endif

파일 f1.c:

#include "f1.h"

float h[] = F1_ARRAY;

#define N (sizeof(h)/sizeof(*h))

...

그렇다면 float h[N] = { #float "f1.h" }를 사용하는 것이 일반적인 방법입니까?

정상은 아니지만 유효합니다(컴파일러에 의해 받아들여집니다).

이 방법의 장점: 더 나은 솔루션을 생각해내기 위해 필요한 약간의 노력을 덜 수 있습니다.

단점:

  • 코드의 WTF/SLOC 비율을 높입니다.
  • 클라이언트 코드와 포함된 코드 모두에서 비정상적인 구문을 도입합니다.
  • f1.h의 기능을 이해하기 위해서는 어떻게 사용되는지 확인해야 합니다(이는 이 괴물을 설명하기 위해 프로젝트에 추가 문서를 추가하거나 사람들이 그 의미를 알기 위해 코드를 읽어야 한다는 의미입니다. 어느 솔루션도 허용되지 않습니다).

이것은 코드를 작성하기 전에 추가로 20분 동안 고민하는 것으로, 프로젝트의 수명 동안 코드와 개발자를 저주하는 데 수십 시간을 할애할 수 있는 경우 중 하나입니다.

아니, 그건 정상적인 관행이 아니야.

이러한 형식을 직접 사용하는 것은 거의 또는 전혀 이점이 없습니다.대신 데이터를 별도의 소스 파일로 생성하거나 적어도 이 경우 완전한 정의를 형성할 수 있습니다.


그러나 X-Macros같은 랜덤한 장소에 파일을 포함하는 "패턴"이 있습니다.

X-macro는 컬렉션을 한 번 정의하고 다양한 장소에서 사용하는 것입니다.전체의 일관성을 보증하는 단일 정의.간단한 예로서 다음 사항을 고려합니다.

// def.inc
MYPROJECT_DEF_MACRO(Error,   Red,    0xff0000)
MYPROJECT_DEF_MACRO(Warning, Orange, 0xffa500)
MYPROJECT_DEF_MACRO(Correct, Green,  0x7fff00)

다양한 방법으로 사용할 수 있게 되었습니다.

// MessageCategory.hpp
#ifndef MYPROJECT_MESSAGE_CATEGORY_HPP_INCLUDED
#define MYPROJECT_MESSAGE_CATEGORY_HPP_INCLUDED

namespace myproject {

    enum class MessageCategory {
#   define MYPROJECT_DEF_MACRO(Name_, dummy0_, dummy1_) Name_,
#   include "def.inc"
#   undef MYPROJECT_DEF_MACRO
    NumberOfMessageCategories
    }; // enum class MessageCategory

    enum class MessageColor {
#   define MYPROJECT_DEF_MACRO(dumm0_, Color_, dummy1_) Color_,
#   include "def.inc"
#   undef MYPROJECT_DEF_MACRO
    NumberOfMessageColors
    }; // enum class MessageColor

    MessageColor getAssociatedColorName(MessageCategory category);

    RGBColor getAssociatedColorCode(MessageCategory category);

} // namespace myproject

#endif // MYPROJECT_MESSAGE_CATEGORY_HPP_INCLUDED

오래전에 사람들은 프리프로세서를 너무 많이 사용했다.를 들어, XPM 파일 포맷을 참조해 주세요.이 포맷은, 다음의 작업을 실시할 수 있도록 설계되어 있습니다.

#include "myimage.xpm"

C코드로 입력해 주세요.

더 이상 좋지 않은 것 같아요.

는 「 」와 .C 저는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★C

프리프로세서를 과도하게 사용하는 이유는 무엇입니까?

「」#include디렉티브는 소스 코드를 포함하는 것을 목적으로 합니다.이 경우 및 OP의 경우 실제 소스 코드가 아니라 데이터입니다.

왜 나쁘다고 생각되는 거죠?

왜냐하면 그것은 매우 융통성이 없기 때문이다.전체 응용 프로그램을 다시 컴파일하지 않으면 이미지를 변경할 수 없습니다.컴파일할 수 없는 코드가 생성되므로 같은 이름의 두 이미지를 포함할 수도 없습니다.OP의 경우 애플리케이션을 다시 컴파일하지 않으면 데이터를 변경할 수 없습니다.

또 다른 문제는 데이터와 소스 코드 간에 엄격한 결합이 발생한다는 것입니다. 예를 들어 데이터 파일에는 적어도 에 의해 지정된 수의 값이 포함되어 있어야 합니다.N★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

또한 긴밀하게 결합하면 데이터에 형식이 지정됩니다. 예를 들어 10x10 매트릭스 값을 저장하는 경우 소스 코드에 단일 차원 배열 또는 2차원 배열을 사용할 수 있습니다.한 형식에서 다른 형식으로 전환하면 데이터 파일이 변경됩니다.

데이터 로딩 문제는 표준 I/O 기능을 사용하면 쉽게 해결할 수 있습니다.일부 기본 이미지를 포함해야 하는 경우 소스 코드의 이미지에 대한 기본 경로를 지정할 수 있습니다.이를 통해 사용자는 적어도 이 값을 변경할 수 있습니다.#define ★★★★★★★★★★★★★★★★★」-D컴파일 시 옵션) 또는 재컴파일 없이 이미지 파일을 업데이트합니다.

FIR 와 OP 'FIR'의 를 보다 할 수 .x, y츠미야 해서 만들 수 요.struct이 가치들을 함께 유지하는 것.이 코드는 비효율적이지 않을 뿐만 아니라 다른 코피스를 사용하더라도 재사용할 수 있게 됩니다.사용자가 파일 경로를 재정의하는 명령줄 매개 변수를 전달하지 않는 한 기본 파일에서 시작 시 요소를 로드할 수 있습니다.이를 통해 글로벌 변수가 불필요해지고 프로그래머의 의도를 명확하게 할 수 있습니다.같은 FIR 기능을 2개의 스레드로 사용할 수도 있습니다.단, 각 스레드에 고유의 FIR 기능이 있는 경우struct.

언제 허용되나요?

데이터의 동적 로드를 수행할 수 없는 경우.이 경우 데이터를 정적으로 로드해야 하며 이러한 기술을 사용해야 합니다.

파일에 액세스 할 수 없다는 것은 매우 제한된 플랫폼에 대해 프로그래밍을 하고 있다는 것을 의미하기 때문에 트레이드오프를 수행해야 한다는 것을 유념해야 합니다.예를 들어 마이크로컨트롤러에서 코드가 실행되고 있는 경우에 해당됩니다.

하지만 그런 경우에도 난 진짜를 만들고 싶어C합니다.

를 들어,의 「」 「」 「」 「」를 지정한다.C함수를 사용하여 계수를 반환할 수 있습니다. ★★★★★★★★★★★★★★★★★.C그런 다음 함수를 2개의 다른 파일로 정의할 수 있습니다.하나는 개발 목적으로 I/O를 사용하고 다른 하나는 릴리스 빌드를 위해 정적 데이터를 반환할 수 있습니다.이치노

툴을 하여 소스 코드를 파일을 으로 .C생성하거나 도구에 된 C .한 양의 코드가 포함된 C 파일을 생성하거나 코드 사용이 필요한 경우가 있습니다.#include다양한 "지시" 방식으로 지시합니다.이 방법들 중 후자가 비록 짜증나기는 하지만 종종 가장 덜 나쁜 방법일 수도 있다고 제안하고 싶다.

는 이 의 사용을 것이 좋습니다..h헤더 파일과 관련된 일반 규칙을 준수하지 않는 파일(예를 들어 메서드 정의 포함, 공간 할당, 비정상적인 포함 컨텍스트(예를 들어 메서드 중간)를 요구함)의 접미사. 정의된 매크로에 여러 개 포함시킬 필요가 있습니다...c ★★★★★★★★★★★★★★★★★」.cpp 통해 의 경우#include스탠드아론에서 되지 않는 한 [들어 수 fooDebug.c#define SPECIAL_FOO_DEBUG_VERSION[newline] #foo.이 다른 두 을 같은 소스에서 중가 " 버전입니다c'는 "normal" 버전입니다.

제 평소 습관은.i다른 C 또는 C++ 소스 파일에서 포함되도록 설계된 인간 생성 파일 또는 기계 생성 파일의 접미사로 사용됩니다. 파일이 기계 생성일 경우 일반적으로 생성 도구의 첫 번째 줄에 해당 파일을 생성하기 위해 사용된 도구를 식별하는 주석을 포함시킵니다.

그런데 제가 사용한 요령 중 하나는 서드파티 툴 없이 배치 파일만 사용하여 프로그램을 빌드할 수 있도록 하고 싶지만 빌드 횟수를 세는 것입니다.제 배치 파일에echo +1 >> vercount.i파일 vercount.c에서 올바르게 기억되면:

const int build_count = 0
#include "vercount.i"
;

그 결과, 서드파티제의 툴에 의존하지 않고, 빌드 마다 증가하는 가치를 얻을 수 있습니다.

프리프로세서가 검출했을 때#include디렉티브는 지정된 파일을 열고 그 내용을 삽입하기만 하면 파일 내용이 디렉티브 위치에 작성되는 것처럼 됩니다.

이미 댓글에서 언급했듯이 이것은 정상적인 관행이 아닙니다.그런 코드를 보면 리팩터링하려고 합니다.

예를들면f1.h이렇게 보일 수 있다

#ifndef _f1_h_
#define _f1_h_

#ifdef N
float h[N] = {
    // content ...
}

#endif // N

#endif // _f1_h_

그리고 .c 파일:

#define N 100 // filter order
#include “f1.h”

float x[N];
float y[N];
// ...

위 코드는 더 개선될 수 있지만(예를 들어 글로벌 제외) 이것은 나에게 좀 더 정상적인 것 같습니다.

다른 모든 사람의 말에 더해서 - 의 내용f1.h다음과 같아야 합니다.

20.0f, 40.2f,
100f, 12.40f
-122,
0

의 텍스트가f1.h문제의 어레이를 초기화합니다.

네, 댓글, 기타 기능 또는 매크로 사용법, 표현식 등이 있을 수 있습니다.

그것은 나에게 있어서 정상적인 관행이다.

프리프로세서를 사용하면 소스 파일을 #include 디렉티브에 의해 조립된 몇 개의 청크로 분할할 수 있습니다.

데이터 초기화 등의 장황한 섹션이나 읽지 않는 섹션으로 코드를 복잡하게 하고 싶지 않은 경우에는 매우 적합합니다.알고 보니 제 레코드 "array initialization" 파일의 길이는 11000줄입니다.

또, 외부 툴에 의해서 코드의 일부가 자동적으로 생성되는 경우에도 사용합니다.툴이 자신의 덩어리를 생성해, 수작업으로 작성한 코드의 나머지 부분에 포함시키는 것은 매우 편리합니다.

프로세서에 따라 몇 가지 대체 구현이 있는 기능이나 인라인 어셈블리를 사용하는 기능 등이 몇 가지 있습니다.포함을 통해 코드를 보다 쉽게 관리할 수 있습니다.

전통적으로 #include 디렉티브는 헤더 파일, 즉 API를 노출하는 선언 세트를 포함하기 위해 사용되어 왔습니다.하지만 어떤 것도 그것을 요구하지 않습니다.

나는 사람들이 재작성하기를 원하고 이것이 악하다고 말하는 것을 읽는다.그래도 어떤 경우에는 사용했어요.일부 사람들이 말했듯이 이것은 프리프로세서 지시사항이며 파일 내용도 포함되어 있습니다.여기 제가 사용한 예가 있습니다. 랜덤 번호를 만드는 것입니다.랜덤한 번호를 작성하기 때문에 런타임에 컴파일 할 때마다 이 작업을 하고 싶지 않습니다.따라서 다른 프로그램(일반적으로 스크립트)은 생성된 숫자로 파일을 채웁니다.이것에 의해, 수작업에 의한 카피가 불필요해지기 때문에, 숫자, 그것을 생성하는 알고리즘, 및 그 외의 세세한 부분까지 간단하게 변경할 수 있습니다.관행을 쉽게 탓할 수는 없다.그러면 그것이 옳은 길일 뿐이다.

변수 선언의 데이터 초기화 부분에 인크루드 파일을 넣는 OP 기술을 오랫동안 사용했습니다.OP와 마찬가지로 포함된 파일이 생성되었습니다.

생성된 .h 파일을 다른 폴더로 분리하여 쉽게 식별할 수 있도록 했습니다.

#include "gensrc/myfile.h"

내가 이클립스를 사용하기 시작했을 때 이 계획은 무너졌다.이클립스 구문 검사는 이 문제를 처리할 만큼 정교하지 않았습니다.구문 오류가 없는 경우 구문 오류를 보고하는 방식으로 반응합니다.

샘플은 Eclipse 메일링 리스트에 보고했지만, 구문 체크의 「수정」에는 그다지 관심이 없는 것 같습니다.

데이터뿐만 아니라 변수 선언 전체를 생성할 수 있도록 코드 생성기를 추가 인수를 사용하도록 변경했습니다.이것으로 구문적으로 올바른 include 파일을 생성합니다.

이클립스를 사용하지 않았더라도 더 나은 솔루션이라고 생각합니다.

Linux 커널에서 IMO라는 예를 찾았습니다.cgroup을 보시면.h 헤더 파일

http://lxr.free-electrons.com/source/include/linux/cgroup.h

지시문을 찾을 수 있습니다.#include <linux/cgroup_subsys.h>매크로의 다른 정의 후 두 번 사용SUBSYS(_x); 이 매크로는 cgroup_subsys.h 내에서 Linux cgroup의 여러 이름을 선언하기 위해 사용됩니다(cgroup에 익숙하지 않은 경우 Linux가 제공하는 사용하기 쉬운 인터페이스로 시스템 부팅 시 초기화해야 합니다).

코드 스니펫에

#define SUBSYS(_x) _x ## _cgrp_id,
enum cgroup_subsys_id {
#include <linux/cgroup_subsys.h>
   CGROUP_SUBSYS_COUNT,
};
#undef SUBSYS

각각SUBSYS(_x)cgroup_disclassys.h에서 선언된 것은 이 유형의 요소가 됩니다.enum cgroup_subsys_id코드 스니펫에 있는 동안

#define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys;
#include <linux/cgroup_subsys.h>
#undef SUBSYS

각각SUBSYS(_x)유형의 변수의 선언이 됩니다.struct cgroup_subsys.

이와 같이 커널 프로그래머는 cgroup_subsys.h만 수정함으로써 cgroup을 추가할 수 있으며 프리 프로세서는 자동으로 관련 열거값/선언을 초기화 파일에 추가합니다.

언급URL : https://stackoverflow.com/questions/26843347/unusual-usage-of-h-file-in-c