diff --git a/CMakeLists.txt b/CMakeLists.txt index fc15cea..bdc5748 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,11 @@ set(APP_SOURCES "src/core/basics/Operations.cpp" "src/core/basics/TypeQualifier.cpp" "src/core/basics/ControlFlow.cpp" + "src/core/linkage/Internal.cpp" + "src/core/linkage/Linkage.cpp" + "src/core/linkage/External.cpp" + "src/core/linkage/sharing/Sharing.cpp" + "src/core/linkage/sharing/external/constants.cpp" "src/core/datatypes/Fundamental.cpp" "src/core/datatypes/CArray.cpp" "src/core/datatypes/CReferences.cpp" diff --git a/src/core/basics/Linkage.cpp b/src/core/basics/Linkage.cpp deleted file mode 100644 index ba768a4..0000000 --- a/src/core/basics/Linkage.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// cppcheck-suppress-file [unreadVariable] -#include -using namespace std; - -namespace { -namespace Internal { -void run() {} -} // namespace Internal - -namespace External { -void run() {} -} // namespace External - -namespace SharingGlobalConstantsAcrossMultipleFiles { -void run() {} -} // namespace SharingGlobalConstantsAcrossMultipleFiles - -} // namespace - -struct LinkageAutoRunner { - LinkageAutoRunner() { - cout << "\n" - << "\n" - << "Linkage\n"; - } -}; - -static LinkageAutoRunner autoRunInstance; diff --git a/src/core/basics/TypeQualifier.cpp b/src/core/basics/TypeQualifier.cpp index a00380f..d8fbdbc 100644 --- a/src/core/basics/TypeQualifier.cpp +++ b/src/core/basics/TypeQualifier.cpp @@ -1,4 +1,7 @@ // cppcheck-suppress-file [unreadVariable] +// A function declared constexpr is implicitly an inline function. +// A static member variable (but not a namespace-scope variable) declared constexpr is implicitly an inline variable. + #include using namespace std; diff --git a/src/core/linkage/External.cpp b/src/core/linkage/External.cpp new file mode 100644 index 0000000..730a5f3 --- /dev/null +++ b/src/core/linkage/External.cpp @@ -0,0 +1,21 @@ +#include "External.h" +#include + +namespace External { // We must define the variable inside the same namespace as its extern declaration; + // otherwise the linker cannot find the correct symbol. + +// 1. Non-Static global variable/ function +int nonStaticVar{1}; +void nonStaticFnc() { + std::cout << "nonStaticFnc\n"; +} + +// 2. Extern Const/constexpr +extern const int EXTERN_CONST_VAR{200}; + +// 3. Namespaces +namespace Name { +int namespaceVar = 123; // Định nghĩa +} + +} // namespace External \ No newline at end of file diff --git a/src/core/linkage/External.h b/src/core/linkage/External.h new file mode 100644 index 0000000..804c04b --- /dev/null +++ b/src/core/linkage/External.h @@ -0,0 +1,9 @@ +namespace External { +// 3. Inline const/constexpr in header file +inline const int INLINE_CONST_VAR{100}; +constexpr int CONSTEXPR_VAR{500}; + +namespace Name { +extern int namespaceVar; +} +} // namespace External diff --git a/src/core/linkage/Internal.cpp b/src/core/linkage/Internal.cpp new file mode 100644 index 0000000..54146f4 --- /dev/null +++ b/src/core/linkage/Internal.cpp @@ -0,0 +1,21 @@ +#include + +namespace Internal { // We must define the variable inside the same namespace as its extern declaration; + // otherwise the linker cannot find the correct symbol. + +// 1. Static global variable/ function +static int g_internal{42}; +static void func_internal() { + std::cout << "func_internal\n"; +} + +// 2. Const/constexpr +const int c_internal{100}; +constexpr int ce_internal{100}; + +// 3. Anonymous namepsace +namespace { +int ns_internal{100}; +} + +} // namespace Internal \ No newline at end of file diff --git a/src/core/linkage/Linkage.cpp b/src/core/linkage/Linkage.cpp new file mode 100644 index 0000000..318c10c --- /dev/null +++ b/src/core/linkage/Linkage.cpp @@ -0,0 +1,51 @@ +// cppcheck-suppress-file [unreadVariable] +#include +#include "External.h" +using namespace std; + +namespace Internal { + +extern int g_internal; // ERROR: g_internal not visible outside Internal.cpp +extern int ce_internal; // ERROR: g_internal not visible outside Internal.cpp +extern int c_internal; // ERROR: g_internal not visible outside Internal.cpp +extern int ns_internal; // ERROR: g_internal not visible outside Internal.cpp + +void func_internal(); // ERROR: helper not visible outside Internal.cpp + +void run() { + // std::cout << g_internal; + // std::cout << ce_internal; + // std::cout << c_internal; + // std::cout << ns_internal; + // func_internal(); +} +} // namespace Internal + +namespace External { +// use extern without initliaizer/forward declaration to access the external global variable/function +extern int nonStaticVar; +void nonStaticFnc(); +extern const int EXTERN_CONST_VAR; + +void run() { + std::cout << nonStaticVar << "\n"; + std::cout << EXTERN_CONST_VAR << "\n"; + std::cout << INLINE_CONST_VAR << "\n"; + std::cout << CONSTEXPR_VAR << "\n"; + std::cout << Name::namespaceVar << "\n"; + nonStaticFnc(); +} + +} // namespace External + +struct LinkageAutoRunner { + LinkageAutoRunner() { + cout << "\n" + << "\n" + << "Linkage\n"; + Internal::run(); + External::run(); + } +}; + +static LinkageAutoRunner autoRunInstance; diff --git a/src/core/linkage/sharing/Sharing.cpp b/src/core/linkage/sharing/Sharing.cpp new file mode 100644 index 0000000..4d87257 --- /dev/null +++ b/src/core/linkage/sharing/Sharing.cpp @@ -0,0 +1,39 @@ +// cppcheck-suppress-file [unreadVariable] +#include +using namespace std; + +#include "external/constants.h" +#include "inline/constants.h" +#include "internal/constants.h" + +namespace InternalWay { +void run() { + std::cout << InternalConstants::avogadro << "\n"; +} +} // namespace InternalWay + +namespace ExternalWay { +void run() { + std::cout << ExternalConstants::avogadro << "\n"; +} +} // namespace ExternalWay + +namespace InlineWay { +void run() { + std::cout << InlineConstants::avogadro << "\n"; +} +} // namespace InlineWay + +struct SharingGlobalConstantsAcrossMultipleFilesngAutoRunner { + SharingGlobalConstantsAcrossMultipleFilesngAutoRunner() { + cout << "\n" + << "\n" + << "SharingGlobalConstantsAcrossMultipleFiles\n"; + + InternalWay::run(); // prefer 2 + ExternalWay::run(); + InlineWay::run(); // prefer 1 + } +}; + +static SharingGlobalConstantsAcrossMultipleFilesngAutoRunner autoRunInstance; diff --git a/src/core/linkage/sharing/external/constants.cpp b/src/core/linkage/sharing/external/constants.cpp new file mode 100644 index 0000000..98ab92e --- /dev/null +++ b/src/core/linkage/sharing/external/constants.cpp @@ -0,0 +1,9 @@ +#include "constants.h" + +namespace ExternalConstants +{ + // We use extern to ensure these have external linkage + extern constexpr double pi { 3.14159 }; + extern constexpr double avogadro { 6.0221413e23 }; + extern constexpr double myGravity { 9.2 }; // m/s^2 -- gravity is light on this planet +} diff --git a/src/core/linkage/sharing/external/constants.h b/src/core/linkage/sharing/external/constants.h new file mode 100644 index 0000000..5865de7 --- /dev/null +++ b/src/core/linkage/sharing/external/constants.h @@ -0,0 +1,22 @@ +// global constants as external variables: + +// Advantages: +// Works prior to C++16. +// Only one copy of each variable is required. +// Only requires recompilation of one file if the value of a constant changes. +// Downsides: +// Forward declarations and variable definitions are in separate files, and must be kept in sync. +// Variables not usable in constant expressions outside of the file in which they are defined. + +#ifndef ECONSTANTS_H +#define ECONSTANTS_H + +namespace ExternalConstants { +// Since the actual variables are inside a namespace, the forward declarations need to be inside a namespace as well +// We can't forward declare variables as constexpr, but we can forward declare them as (runtime) const +extern const double pi; +extern const double avogadro; +extern const double myGravity; +} // namespace ExternalConstants + +#endif \ No newline at end of file diff --git a/src/core/linkage/sharing/inline/constants.h b/src/core/linkage/sharing/inline/constants.h new file mode 100644 index 0000000..7fccbaf --- /dev/null +++ b/src/core/linkage/sharing/inline/constants.h @@ -0,0 +1,22 @@ +// global constants as inline variables: + +// If you need global constants and your compiler is C++17 capable, prefer defining inline constexpr global variables in a header file. +// Advantages: +// Can be used in constant expressions in any translation unit that includes them. +// Only one copy of each variable is required. +// Downsides: +// Only works in C++17 onward. +// Changing anything in the header file requires recompiling files including the header. + +#ifndef ICONSTANTS_H +#define ICONSTANTS_H + +// define your own namespace to hold constants +namespace InlineConstants { +inline constexpr double pi{3.14159}; // note: now inline constexpr +inline constexpr double avogadro{6.0221413e23}; +inline constexpr double myGravity{ + 9.2}; // m/s^2 -- gravity is light on this planet + // ... other related constants +} // namespace InlineConstants +#endif \ No newline at end of file diff --git a/src/core/linkage/sharing/internal/constants.h b/src/core/linkage/sharing/internal/constants.h new file mode 100644 index 0000000..1dc5cd8 --- /dev/null +++ b/src/core/linkage/sharing/internal/constants.h @@ -0,0 +1,21 @@ + +// global constants as internal variables: +// Advantages: +// Works prior to C++16. +// Can be used in constant expressions in any translation unit that includes them. +// Downsides: +// Changing anything in the header file requires recompiling files including the header. +// Each translation unit including the header gets its own copy of the variable. + +#ifndef INCONSTANTS_H +#define INCONSTANTS_H + +// Define your own namespace to hold constants +namespace InternalConstants { +// Global constants have internal linkage by default +constexpr double pi{3.14159}; +constexpr double avogadro{6.0221413e23}; +constexpr double myGravity{9.2}; // m/s^2 -- gravity is light on this planet + // ... other related constants +} // namespace InternalConstants +#endif \ No newline at end of file