__CURTOR__ 전 프로세서 매크로를 사용한 적이 있는 사람이 있는가?
그__COUNTER__
기호는 VC++와 GCC에서 제공하며, 사용할 때마다 음이 아닌 적분 값이 증가한다.
누가 써 본 적이 있는지, 표준화할 만한 가치가 있을 만한 것인지에 대해 알고 싶다.
__COUNTER__
독특한 이름이 필요한 곳이라면 어디든 유용하다.나는 그것을 RAII 스타일 잠금장치와 스택에 광범위하게 사용해 왔다.고려 사항:
struct TLock
{
void Lock();
void Unlock();
}
g_Lock1, g_Lock2;
struct TLockUse
{
TLockUse( TLock &lock ):m_Lock(lock){ m_Lock.Lock(); }
~TLockUse(){ m_Lock.Unlock(); }
TLock &m_Lock;
};
void DoSomething()
{
TLockUse lock_use1( g_Lock1 );
TLockUse lock_use2( g_Lock2 );
// ...
}
자물쇠의 용도에 이름을 붙이는 것은 지루하고, 만약 그것들이 모두 블록의 맨 위에 선언되지 않는다면, 심지어 오류의 원인이 될 수도 있다.지금 하고 있는지 어떻게 알아?lock_use4
또는lock_use11
나는 가 없다 또한 네임스페이스의 불필요한 오염이다 - 나는 결코 이름별로 자물쇠 사용물체를 언급할 필요가 없다.그래서 나는 사용한다.__COUNTER__
:
#define CONCAT_IMPL( x, y ) x##y
#define MACRO_CONCAT( x, y ) CONCAT_IMPL( x, y )
#define USE_LOCK( lock ) TLockUse MACRO_CONCAT( LockUse, __COUNTER__ )( lock )
void DoSomething2()
{
USE_LOCK( g_Lock1 );
USE_LOCK( g_Lock2 );
// ...
}
하지만 내가 물체 잠금 장치라고 불렀다는 사실에 집착하지 마라. 짝을 지어 불러야 하는 어떤 기능도 이 패턴에 들어맞는다.주어진 블록에서 동일한 "잠금"을 여러 번 사용할 수도 있다.
누가 써본 적이 있는지 알고 싶은데
네, 하지만 이번 Q&A의 많은 사례에서 보시다시피,__LINE__
표준화되어 있는 , 또한 대부분의 경우 충분할 것이다.
__COUNTER__
횟수가 매번 1회씩 증가하거나 여러 번 연속성을 가져야 하는 경우에만 정말로 필요하다.#include
파일들
표준화할 만한 가치가 있는 것인지?
__COUNTER__
,와는 달리__LINE__
는 어떤 헤더 파일이 포함되고 어떤 순서에 따라 달라지기 때문에 매우 위험하다.만약 둘이면.cpp
파일(파일)은 사용하는 헤더 파일을 포함한다.__COUNTER__
그러나 헤더 파일은 다른 인스턴스에서 서로 다른 카운트 시퀀스를 얻으며, 동일한 항목에 대한 다른 정의를 사용할 수 있으며 단일 정의 규칙을 위반할 수 있다.
단일 정의 규칙 위반은 매우 잡기 어렵고 잠재적으로 버그와 보안 위험을 발생시킬 수 있다.의 몇 가지 사용 사례__COUNTER__
확장성의 단점과 부족을 실제로 능가하지는 마십시오.
비록 당신이 사용하지 않는 코드를 발송하지 않더라도__COUNTER__
, 열거 시퀀스를 프로토타입화할 때 유용할 수 있으며, 멤버십이 구체화되기 전에 이름을 할당하는 번거로움을 덜 수 있다.
xCover 코드 적용 범위 라이브러리에서 실행이 통과하는 라인을 표시하고 적용되지 않는 라인을 찾는데 사용되며,
클래스 유형 ID 생성 중(C++)
써본 적이 있다.__COUNTER__
객체 지향 게임에서 엔티티 & 콜라이더에 대한 타입 ID를 자동으로 생성한다.
이 게임은 기능성을 얻기 위해 다형성을 사용한다.하위 개체를 직렬화하기 위해 엔티티 하위 유형을 저장하고 씬(scene) 저장 및 로드를 위해 하위 유형을 직렬화/직렬화하는 방법을 찾아야 했다.저장 파일에서 엔티티를 읽을 때(디시리얼라이징) 어떤 속성을 읽어야 하는지 알아야 했다.__COUNTER__
, 나는 각 엔티티 클래스에 대해 고유하고 일정한 ID를 가지고 있으며, 이 ID를 사용하여 적절한 엔티티 유형으로 로딩할 수 있다.
이 접근법은 새로운 기업 유형을 일련화할 수 있도록 하기 위해 내가 추가해야 할 것은typeID = __COUNTER__;
기본 ID를 덮어쓸 생성자 내에서.스프라이트의 경우:
Sprite(/* TODO: Sprite Arguments */) : Entity(/* TODO: Entity Arguments */) {
typeID = __COUNTER__;
}
아이오스트림 과부하 개요:
friend std::ostream& operator<<(std::ostream& os, const Sprite& rhs) {
return os << /* TODO: Outline Output */;
}
friend std::istream& operator>>(std::istream& is, Sprite& rhs) {
return is >> /* TODO: Outline Input */;
}
이것은 당신의 수업을 위한 타입 ID를 생성하는 매우 가벼운 접근법이며, 복잡한 논리를 많이 피한다.전처리기 명령으로 그것은 꽤 기본적이지만, 그것은 몇몇 주요 가전제품에 유용한 도구를 제공한다.
참고: 카운터를 호출할 때 ID 값을 0으로 다시 시작하려면 첫 번째 ID 생성에 값을 저장하고 이후 모든 ID를 해당 값만큼 빼십시오.
읽어줘서 고마워! -YZM
TensorFlow의 매크로에는 사용법이 있다.각 TensorFlow Op는 구현으로 하나 이상의 커널을 가질 수 있다.이 낟알들은 등기소에 등록되어 있다.커널의 등록은 글로벌 변수를 정의함으로써 이루어진다 - 변수의 생성자가 등록을 할 수 있다.여기서 저자는 다음을 사용한다.__COUNTER__
각 글로벌 변수에 고유한 이름을 부여한다.
#define REGISTER_KERNEL_BUILDER(kernel_builder, ...) \
REGISTER_KERNEL_BUILDER_UNIQ_HELPER(__COUNTER__, kernel_builder, __VA_ARGS__)
#define REGISTER_KERNEL_BUILDER_UNIQ_HELPER(ctr, kernel_builder, ...) \
REGISTER_KERNEL_BUILDER_UNIQ(ctr, kernel_builder, __VA_ARGS__)
#define REGISTER_KERNEL_BUILDER_UNIQ(ctr, kernel_builder, ...) \
static ::tensorflow::kernel_factory::OpKernelRegistrar \
registrar__body__##ctr##__object( \
SHOULD_REGISTER_OP_KERNEL(#__VA_ARGS__) \
? ::tensorflow::register_kernel::kernel_builder.Build() \
: nullptr, \
#__VA_ARGS__, [](::tensorflow::OpKernelConstruction* context) \
-> ::tensorflow::OpKernel* { \
return new __VA_ARGS__(context); \
});
DEBUG 매크로 외에는 어떤 용도로도 사용해 본 적이 없다.라고 말할 수 있는 것이 편리하다.
#define WAYPOINT \
do { if(dbg) printf("At marker: %d\n", __COUNTER__); } while(0);
ClickHouse의 메트릭스 시스템에 사용된다.
namespace CurrentMetrics
{
#define M(NAME) extern const Metric NAME = __COUNTER__;
APPLY_FOR_METRICS(M)
#undef M
constexpr Metric END = __COUNTER__;
std::atomic<Value> values[END] {}; /// Global variable, initialized by zeros.
const char * getDescription(Metric event)
{
static const char * descriptions[] =
{
#define M(NAME) #NAME,
APPLY_FOR_METRICS(M)
#undef M
};
return descriptions[event];
}
Metric end() { return END; }
}
드라이버 심 레이어에 사용했는데, 적어도 한 대의 물리적 드라이버가 활성화되었는지 확인해야 했다.
예를 들면 다음과 같다.
#if defined( USE_DRIVER1 )
#include "driver1.h"
int xxx1 = __COUNTER__;
#endif
#if defined( USE_DRIVER2 )
#include "driver2.h"
int xxx2 = __COUNTER__;
#endif
#if __COUNTER__ < 1
#error Must enable at least one driver.
#endif
나는 그것을 컴파일 시간 어설션 매크로에서 사용해 매크로가 독특하게 타이페프의 이름을 만들도록 했다.참조
만약 당신이 그 세부사항들을 원한다면.
그것은 부스트에 의해 사용된다.스택리스 코루틴을 구현하는 Asio.
결과 코루틴은 다음과 같이 보인다.
struct task : coroutine
{
...
void operator()()
{
reenter (this)
{
while (... not finished ...)
{
... do something ...
yield;
... do some more ...
yield;
}
}
}
...
};
__COUNTER__
런타임에 문자열을 암호화할 때 암호화 키에 대한 카운터를 어딘가에 저장하지 않고 모든 문자열에 고유 키가 있는지 확인하기 위해 Counter를 사용하면 매우 유용하다!
나는 그것을 나의 것에 사용한다.XorString
런타임에 문자열을 해독하는 헤더 라이브러리 1개. 그래서 해커/크래커들이 내 이진 파일을 보려고 하면 거기서 문자열을 찾지 못하지만 프로그램이 실행되면 모든 문자열이 해독되어 정상적으로 표시된다.
#pragma once
#include <string>
#include <array>
#include <cstdarg>
#define BEGIN_NAMESPACE( x ) namespace x {
#define END_NAMESPACE }
BEGIN_NAMESPACE(XorCompileTime)
constexpr auto time = __TIME__;
constexpr auto seed = static_cast< int >(time[7]) + static_cast< int >(time[6]) * 10 + static_cast< int >(time[4]) * 60 + static_cast< int >(time[3]) * 600 + static_cast< int >(time[1]) * 3600 + static_cast< int >(time[0]) * 36000;
// 1988, Stephen Park and Keith Miller
// "Random Number Generators: Good Ones Are Hard To Find", considered as "minimal standard"
// Park-Miller 31 bit pseudo-random number generator, implemented with G. Carta's optimisation:
// with 32-bit math and without division
template < int N >
struct RandomGenerator
{
private:
static constexpr unsigned a = 16807; // 7^5
static constexpr unsigned m = 2147483647; // 2^31 - 1
static constexpr unsigned s = RandomGenerator< N - 1 >::value;
static constexpr unsigned lo = a * (s & 0xFFFF); // Multiply lower 16 bits by 16807
static constexpr unsigned hi = a * (s >> 16); // Multiply higher 16 bits by 16807
static constexpr unsigned lo2 = lo + ((hi & 0x7FFF) << 16); // Combine lower 15 bits of hi with lo's upper bits
static constexpr unsigned hi2 = hi >> 15; // Discard lower 15 bits of hi
static constexpr unsigned lo3 = lo2 + hi;
public:
static constexpr unsigned max = m;
static constexpr unsigned value = lo3 > m ? lo3 - m : lo3;
};
template <>
struct RandomGenerator< 0 >
{
static constexpr unsigned value = seed;
};
template < int N, int M >
struct RandomInt
{
static constexpr auto value = RandomGenerator< N + 1 >::value % M;
};
template < int N >
struct RandomChar
{
static const char value = static_cast< char >(1 + RandomInt< N, 0x7F - 1 >::value);
};
template < size_t N, int K, typename Char >
struct XorString
{
private:
const char _key;
std::array< Char, N + 1 > _encrypted;
constexpr Char enc(Char c) const
{
return c ^ _key;
}
Char dec(Char c) const
{
return c ^ _key;
}
public:
template < size_t... Is >
constexpr __forceinline XorString(const Char* str, std::index_sequence< Is... >) : _key(RandomChar< K >::value), _encrypted{ enc(str[Is])... }
{
}
__forceinline decltype(auto) decrypt(void)
{
for (size_t i = 0; i < N; ++i) {
_encrypted[i] = dec(_encrypted[i]);
}
_encrypted[N] = '\0';
return _encrypted.data();
}
};
//--------------------------------------------------------------------------------
//-- Note: XorStr will __NOT__ work directly with functions like printf.
// To work with them you need a wrapper function that takes a const char*
// as parameter and passes it to printf and alike.
//
// The Microsoft Compiler/Linker is not working correctly with variadic
// templates!
//
// Use the functions below or use std::cout (and similar)!
//--------------------------------------------------------------------------------
static auto w_printf = [](const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf_s(fmt, args);
va_end(args);
};
static auto w_printf_s = [](const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf_s(fmt, args);
va_end(args);
};
static auto w_sprintf = [](char* buf, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
};
static auto w_sprintf_ret = [](char* buf, const char* fmt, ...) {
int ret;
va_list args;
va_start(args, fmt);
ret = vsprintf(buf, fmt, args);
va_end(args);
return ret;
};
static auto w_sprintf_s = [](char* buf, size_t buf_size, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vsprintf_s(buf, buf_size, fmt, args);
va_end(args);
};
static auto w_sprintf_s_ret = [](char* buf, size_t buf_size, const char* fmt, ...) {
int ret;
va_list args;
va_start(args, fmt);
ret = vsprintf_s(buf, buf_size, fmt, args);
va_end(args);
return ret;
};
//Old functions before I found out about wrapper functions.
//#define XorStr( s ) ( XorCompileTime::XorString< sizeof(s)/sizeof(char) - 1, __COUNTER__, char >( s, std::make_index_sequence< sizeof(s)/sizeof(char) - 1>() ).decrypt() )
//#define XorStrW( s ) ( XorCompileTime::XorString< sizeof(s)/sizeof(wchar_t) - 1, __COUNTER__, wchar_t >( s, std::make_index_sequence< sizeof(s)/sizeof(wchar_t) - 1>() ).decrypt() )
//Wrapper functions to work in all functions below
#define XorStr( s ) []{ constexpr XorCompileTime::XorString< sizeof(s)/sizeof(char) - 1, __COUNTER__, char > expr( s, std::make_index_sequence< sizeof(s)/sizeof(char) - 1>() ); return expr; }().decrypt()
#define XorStrW( s ) []{ constexpr XorCompileTime::XorString< sizeof(s)/sizeof(wchar_t) - 1, __COUNTER__, wchar_t > expr( s, std::make_index_sequence< sizeof(s)/sizeof(wchar_t) - 1>() ); return expr; }().decrypt()
END_NAMESPACE
나는 사용할 작정이다__COUNTER__
코드베이스의 모든 파일에 고유한 식별자를 부여하여 고유한 코드가 내장된 시스템의 ASSITE 로깅에 사용될 수 있도록 한다.
이 방법은 파일 이름을 저장하는 데 문자열을 사용하는 것보다 훨씬 더 효율적이다(사용).__FILE__
), 특히 작은 ROM을 가진 임베디드 시스템.나는 이 기사를 읽으면서 그 생각을 생각했다. Embedded.com에서 자신을 주장하라.GCC 기반 컴파일러로만 작동한다는 게 아쉽다.
기능을 제대로 이해하고 있다면 Perl에서 작업할 때 기존 GUI에 이벤트 로깅 기능을 추가하면서 해당 기능을 갖고 싶었다.필요한 손 테스트(sigh)를 통해 완벽한 커버리지를 보장받고 싶었기 때문에 모든 테스트 포인트를 파일에 기록했고,__counter__
가치관 덕분에 커버리지에서 빠진 것을 쉽게 볼 수 있었다.그대로, 나는 그에 상응하는 것을 손으로 코딩했다.
이 기사에서 고유한 유형을 생성하기 위해 사용했었습니다: http://www.codeproject.com/Articles/42021/Sealing-Classes-in-C
__COUNTER__
다른 것과 달리 독특하다고 보장된다.__LINE__
어떤 컴파일러들은 허락한다.__LINE__
리셋되다#vms 파일도 재설정됨__LINE__
.
우리의 코드에서 우리는 일부 제품에 대한 테스트 케이스를 추가하는 것을 잊었다.나는 지금 매크로를 몇 개 구현해서 우리는 우리가 추가하거나 제거하는 각 제품에 대한 테스트 케이스를 컴파일 시간에 가지고 있다고 주장할 수 있다.
이 블로그 게시물에서 이 게시물은defer
C++11의 골랑 명세서
template <typename F>
struct privDefer {
F f;
privDefer(F f) : f(f) {}
~privDefer() { f(); }
};
template <typename F>
privDefer<F> defer_func(F f) {
return privDefer<F>(f);
}
#define DEFER_1(x, y) x##y
#define DEFER_2(x, y) DEFER_1(x, y)
#define DEFER_3(x) DEFER_2(x, __COUNTER__)
#define defer(code) auto DEFER_3(_defer_) = defer_func([&](){code;})
그런 다음 다음을 수행할 수 있다.
int main()
{
FILE* file = open("file.txt");
defer(fclose(file));
// use the file here
// ....
}
나는 그것이 UI에 단계를 표시하는 데 유용하다는 것을 알았다.이렇게 하면 단계 라벨이 잘못 표시될 염려 없이 단계를 추가, 제거 또는 재주문하기가 정말 쉽다.
#include <iostream>
#define STR_IMPL(s) #s
#define STR(s) STR_IMPL(s)
#define STEP STR(__COUNTER__) ": "
int main()
{
std::cout
<< STEP "foo\n"
<< STEP "bar\n"
<< STEP "qux\n"
;
}
출력:
0: foo
1: bar
2: qux
0이 아닌 1부터 시작하는 것은 연습으로 남는다.
'Programing' 카테고리의 다른 글
스프링 부트 및 Vue.js가 포함된 사용자 지정 로그인 페이지 (0) | 2022.04.26 |
---|---|
Nuxt - 여러 요청이 있는 비동기 데이터 (0) | 2022.04.26 |
Vue.js의 반응성은 어떻게 작용하는가? (0) | 2022.04.26 |
Java의 변수 유형을 어떻게 아십니까? (0) | 2022.04.26 |
다른 구성 요소가 있는 Vue JS 루프 (0) | 2022.04.26 |