Forked from EvanMcBroom/pic-and-string-literals-2.md
Created
October 13, 2023 08:17
-
-
Save cvlabsio/33c4d819a14f0f977a9960786aaa261f to your computer and use it in GitHub Desktop.
Revisions
-
EvanMcBroom revised this gist
Oct 6, 2021 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -57,7 +57,7 @@ constexpr char picString2[]{ "abc" }; _"Woohoo!"_ There is no more need to break out a string literal to use it in PIC code. The technique can also be used in a macro function to ensure that the `constexpr` keyword is not forgotten. ```c++ -
EvanMcBroom revised this gist
Oct 6, 2021 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -27,14 +27,14 @@ The below code is how to create an `initializer_list` to do just that but there // Return an initializer sequence (ex. {'a', 'b', 'c'}) template <typename T, std::size_t N, std::size_t... Index> constexpr std::initializer_list<char> make_init_seq(const T(&input)[N], const std::index_sequence<Index...>) { return { input[Index]... }; } // Return an initializer sequence for a given string literal template <typename T, std::size_t N> constexpr auto str_literal_init_seq(const T(&input)[N]) { constexpr std::make_index_sequence<N> sequence; return make_init_seq(std::forward<decltype(input)>(input), sequence); } ``` @@ -65,7 +65,7 @@ The technique can also be used in a macro function to ensure that the `constexpr #define pic_wstring(NAME, STRING) constexpr wchar_t NAME[]{ STRING } void f() { pic_string(picString, "Hello World!\n"); std::cout << picString; } ``` -
EvanMcBroom created this gist
Oct 6, 2021 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,71 @@ # PIC and String Literals Part 2 I previously wrote about how to use macro metaprogramming to simplify using string literals in position independent code (PIC). The results are summarized in the below code snippet and the article [can be read on GitHub](https://gist.github.com/EvanMcBroom/f5b1bc53977865773802d795ade67273). ```cpp void f() { // Example 1: The Pic idiom for instantiating a string char picString1[]{ 'a', 'b', 'c' }; // Example 2: Using a metaprogramming technique from the // previous article to achieve the same result PIC_STRING(picString2, 5, "abc\n"); } ``` I resently revisited the topic because I was bothered by the solution's reliance on macro metaprogramming and a third party library to accomplish such a small goal. ## Template Metaprogramming A possible alternative solution was to use template metaprogramming which would likely not require much code or a third party library. Ideally we would use a template function to generate the initializer list of characters to instantiate a local character array at compile time. The below code is how to create an `initializer_list` to do just that but there is one issue.... ```c++ // Return an initializer sequence (ex. {'a', 'b', 'c'}) template <typename T, std::size_t N, std::size_t... Index> constexpr std::initializer_list<char> make_init_seq(const T(&input)[N], const std::index_sequence<Index...>) { return { input[Index]... }; } // Return an initializer sequence for a given string literal template <typename T, std::size_t N> constexpr auto str_literal_init_seq(const T(&input)[N]) { constexpr std::make_index_sequence<N> sequence; return make_init_seq(std::forward<decltype(input)>(input), sequence); } ``` The `initializer_list` class that is created in `make_init_seq` will internally store pointers to the start and end of the `input` array. Ultimately that means that the return statement can not be used in a constant expression, and in turn, neither function as well. Meaning that any string literal used in conjunction with calling `str_literal_init_seq` will require the string to be stored in the `.data` section. Although approaching the problem by using templates to generate an initializer list of character arrays seemed promising at first, creating a solution using this technique was not viable. ## The Perfect Solution Luckily, the previous investigation caused me to stumble across the assembly that is generated for local arrays that are marked as `constexpr`. What is generated is _exactly_ the PIC assembly that I have been trying to achieve regardless of what compiler optimizations are enabled! Knowing this, the below local character array initializations generate the same assembly code. ```c++ char picString1[]{ 'a', 'b', 'c' }; constexpr char picString2[]{ "abc" }; ``` _"Woohoo!"_ There is no more need to break out a string literal to use it in PIC code. The technique can also be used in a macro function to ensure that the `constexpr` keyword is used. ```c++ #define pic_string(NAME, STRING) constexpr char NAME[]{ STRING } #define pic_wstring(NAME, STRING) constexpr wchar_t NAME[]{ STRING } void f() { pic_string(picString, "Hello World!\n"); std::cout << picString; } ```