I have code in C that compiles and works correctly and I would like to use similar code in C++:
static const char* aTable[12] = {
[4]="seems",
[6]=" it ",
[8]="works",};
int main(){
printf("%s%s%s", aTable[4],aTable[6],aTable[8]);
return 0;
}
Now if I put it in a .c file and compiles with gcc it works. But, if I put it in a .cpp file and compile it with g++, I get the following errors:
test_cpp.cpp:5:3: error: expected identifier before numeric constant
test_cpp.cpp:5:4: error: type '<lambda>' with no linkage used to declare function 'void<lambda>::operator()() const' with linkage [-fpermissive]
test_cpp.cpp: In lambda function: test_cpp.cpp:5:5: error: expected '{' before '=' token
test_cpp.cpp: At global scope: test_cpp.cpp:5:5: warning: lambda expressions only available with
-std=c++0x or -std=gnu++0x [enabled by default]
test_cpp.cpp:5:6: error: no match for 'operator=' in '{} = "seems"' test_cpp.cpp:5:6: note: candidate is: test_cpp.cpp:5:4: note: <lambda()>&<lambda()>::operator=(const<lambda()>&)
test_cpp.cpp:5:4: note: no known conversion for argument 1 from 'const char [6]' to 'const<lambda()>&'
test_cpp.cpp:6:3: error: expected identifier before numeric constant
test_cpp.cpp:6:4: error: type '<lambda>' with no linkage used to declare function 'void<lambda>::operator()() const' with linkage [-fpermissive]
Is there a way to express that I am not declaring a lambda function, just trying to fill a table?
I would like to keep the following part :
[4]="seems",
[6]=" it ",
[8]="works",
because it comes from an autogenerated file...
You can mix C and C++ code easily.
You should keep the C code to be compiled with C compiler (gcc), rest of the code can be C++ and be compiled with C++ compiler (g++). then link all object (.o) files together.
like this:
file name: a.c
const char* aTable[12] = {
[4]="seems",
[6]=" it ",
[8]="works",};
file name: b.cpp
#include <cstdio>
extern "C" const char* aTable[12];
int main(){
printf("%s%s%s", aTable[4],aTable[6],aTable[8]);
return 0;
}
Now compile:
gcc -c a.c -o a.o
g++ -c b.cpp -o b.o
g++ b.o a.o -o all.out
Now run the executable (all.out) and you'll see that everything will work.
Just note that for functions you'll need to add extern "C" before the declaration in the cpp file.
There's no way to do this. C++ never adopted this particular C syntax.
In your case, since the table is auto-generated, I would just put it in a C file. As long as it's not marked static, it can be accessed from C++ code without problems.
[4]= is a designated initializer, one of the C features not supported by C++.
Here is a list that tries to list which C99 features that are supported by C++17. Scroll down to the bottom to see which ones that are not supported.
It is important to realize that C++ is by no means a superset of C.
Designated initialisers not being supported by C++ already mentioned – if you insist on C++, you could write a wrapper class with a constructor instead:
class Table
{
std::array<char const*, 12> data;
public:
Table()
{
data[4] = "seems";
data[6] = " it ";
data[8] = "works";
}
char const* operator[](unsigned int index) const
{
return data[index];
}
} aTable;
Did not test the code, so if you find a bug, feel free to fix it yourself...
As said above, this type of initialization is not supported in C++, but you could use lambda function to initialize static array<const char*, 12> like this:
#include <array>
#include <cstdio>
static const std::array<const char*, 6> aTable = []() {
std::array<const char*, 6> table;
table[0] = "Hello";
table[3] = ", ";
table[5] = "world!";
return std::move(table);
}();
int main() {
printf("%s%s%s\n", aTable[0], aTable[3], aTable[5]);
return 0;
}
Demo on coliru
Notable, that compiler will do RVO here, and the initialization will be performed in-place. This is assembly generated by g++-5.4.0:
<_GLOBAL__sub_I_main>:
movq $0x40064c,0x200bc5(%rip) # 601060 <_ZL6aTable>
movq $0x400652,0x200bd2(%rip) # 601078 <_ZL6aTable+0x18>
movq $0x400655,0x200bd7(%rip) # 601088 <_ZL6aTable+0x28>
retq
Related
I am hoping to receive some input on an issue I encountered while attempting to learn c++20 modules.
In short, I would like a namespace containing const and/or constexpr variables to be implemented within a module, and import that module into any implementation files applicable.
It works fine with non const / non constexpr variables, however this isn't ideal; I'd like to stick with const and/or constexpr depending on the data types within the namespace.
Please see example below:
// test_module.cpp
module;
#include <string_view>
export module test_module;
export namespace some_useful_ns {
/* produces a compile error when attempting to compile main.cpp */
constexpr std::string_view str_view{"a constexpr string view"};
const char* const chr{"a const char* const"};
/* compiles just fine, but not ideal; prefer const / constexpr
std::string_view str_view{"a non constexpr str view"};
const char* chr{"a const char*"};
*/
}
// main.cpp
#include <iostream>
import test_module;
int main() {
std::cout << some_useful_ns::str_view << std::endl;
std::cout << some_useful_ns::chr << std::endl;
return 0;
}
Compile the two files like below:
g++ -c --std=c++2a -fmodules-ts test_module.cpp
g++ -c --std=c++2a -fmodules-ts main.cpp
g++ main.o test_module.o
Before linking the .o files, I receive the following error when compiling main.cpp like above:
main.cpp: In function ‘int main()’:
main.cpp:6:38: error: ‘str_view’ is not a member of ‘some_useful_ns’
6 | std::cout << some_useful_ns::str_view << std::endl;
| ^~~~~~~~
main.cpp:7:38: error: ‘chr’ is not a member of ‘some_useful_ns’
7 | std::cout << some_useful_ns::chr << std::endl;
|
I find this strange since it works fine when I use a non const / non constexpr like the lines commented out in test_module.cpp.
Also, using the const / constexpr works just as expected when using a traditional implementation without modules.
Anyone have a clue as to why I am unable to get this to work successfully with const / constexpr?
In case it helps, I am using gcc (GCC) 11.2.1 20220127
Thanks in advance.
This seems like a compiler bug.
Normally, const-qualified variables have internal linkage, and names with internal linkage cannot be exported. However... there's a specific carveout for such variables which are exported. That is, exported const-qualified variables don't have internal linkage.
struct Foo {
char a[10];
int b;
};
static Foo foo = {.a="bla"};
Compiling the above code gives the following gcc error:
$ gcc -std=gnu++2a test.cpp
C99 designator ‘a’ outside aggregate initializer
I thought that c-string designators in initializer list like these are ok in C++20? What am I missing? I am using gcc version 10.
This is a known bug with GCC: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55227
Unfortunately, you will have to either not use designated initializers or use a different initializer for the array:
static Foo foo = {"bla"};
static Foo foo = {.a={'b', 'l', 'a', 0}};
I got the same error and I dealt with mv my.cpp my.c
You also can find answer in this link:
https://pcbartists.com/firmware/esp32-firmware/designator-outside-aggregate-initializer-solved/
#ifdef __cplusplus
extern "C"
{
#endif
// C code goes here
#ifdef __cplusplus
}
#endif
I use strncpy (from <cstring>), for example:
strncpy(foo.str, "hello", sizeof(foo_t::str));
It seems to be optimized away, therefore generating the same assembly as normal approach in newer GCC (11.3^) and the same as using Artyer solution (the accepted one) of using char array.
Godbolt link: https://godbolt.org/z/9G7b6PT9b
However, the solution might cause warning: missing initializer for member 'foo_t::str' [-Wmissing-field-initializers] if you have the -Wextra warnings enable, but you can use -Wno-missing-field-initializers to exclude it.
By the way, with stucts like that you always have to remember the space is limited, and in many cases you might want leave trailing zero for string end. Using strncpy you can force that by adding:
foo.str[sizeof(foo_t::str) - 1] = 0;
I'm learning now C++ I'm reading the book Effective C++ (Scott Meyers).
In the book, there is an item about const variables, and I try to work with them.
I notice something very interesting that I what to know if it bug in C++:
(I'm working with C++98 standard)
void Test(const int i)
{
int arr[i] = {0};
for (int j = 0; i > j; ++j)
{
arr[j] = i;
}
}
This function will compile and work exactly as I want (create int array on the stack with the size of 'i'. When I remove the 'const' from 'i' it won't compile.
I try this on gcc and clang.
Edit:
link to Compiler Explorer
To catch this kind of mistake in the future the compiler flag you want for both g++ and clang++ is -pedantic. And always remember to specify your language standard or you don't know what you'll get.
$ g++ -std=c++98 -pedantic c++-vla.cpp -o c++-vla
c++-vla.cpp: In function ‘void f(size_t)’:
c++-vla.cpp:3:30: warning: ISO C++ forbids variable length array ‘g’ [-Wvla]
3 | void f(const size_t x) { int g[x]; }
| ^
$ clang++ -std=c++98 -pedantic c++-vla.cpp -o c++-vla
c++-vla.cpp:3:31: warning: variable length arrays are a C99 feature [-Wvla-extension]
void f(const size_t x) { int g[x]; }
^
1 warning generated.
First of all, const in your function signature is ignored by the compiler. So the following two are equivalent:
Test(const int i) {}
Test(int i) {}
Secondly, this isn't valid C++ regardless of whether it compiles or not:
int arr[i] = {0};
It isn't valid because i is not a compile time constant i.e., the value of i has to be known at the time of compilation.
Try on Compiler Explorer
I want to set the array length to be the minimum of a constant and a generic like this:
template <int foo> struct Bar{
void my_func( int const (&my_array)[std::min(5, foo)] ) { /*...*/ }
};
This code compiles with clang++ but not g++ and I need my code to work with both. The error g++ gives is: error: array bound is not an integer constant before ']' token. How I can set the length of this array to be the minimum of foo and 5?
When I use clang++ I run into the problem that I can't get anything to bind to my_array. I want to run something like:
int main() {
static const int var[5] = {0,1,2,3,4};
Bar<5> bar;
bar.my_func(var);
}
But when I try to compile this code in clang++ I get: error: reference to type 'const int [*]' could not bind to an lvalue of type 'const int [5]'.
If I get rid of the std::min() stuff and replace it with foo the code compiles and runs fine.
Notes:
To get this code to compile you'll need to #include <algorithm> or similar to access std::min.
I don't think that this being part of a template should matter but when I try similar things with non-template function such as:
const int const_five = 5;
void new_func( int const (&my_array)[std::min(5,const_five)] ) { /*...*/ }
g++ says: error: variable or field 'new_func' declared void and clang++ says candidate function not viable: no known conversion from 'const int [5]' to 'const int [std::min(5, const_five)]' for 1st argument which both look like similar problems.
For int const (&my_array)[std::min(5, foo)] to compile, you need a version of std::min which is constexpr. It is since C++14.
Check the default value for -std of gcc and clang you use (its version-dependant). Ultimately, compile with -std=c++14.
Provided by StoryTeller, a nice working MCVE.
Keep it simple:
[foo < 5 ? foo : 5]
In C++, it is possible for pointer values to be compile-time constants. This is true, otherwise, non-type template parameters and constexpr won't work with pointers. However, as far as I know, addresses of functions and objects of static storage are known (at least) at link-time rather than compile-time. Following is an illustration:
main.cpp
#include <iostream>
template <int* p>
void f() { std::cout << p << '\n'; }
extern int a;
int main() {
f<&a>();
}
a.cpp
int a = 0;
I'm just wondering how the address of a could possibly be known when compiling main.cpp. I hope somebody could explain this a little to me.
In particular, consider this
template <int* p, int* pp>
constexpr std::size_t f() {
return (p + 1) == (pp + 7) ? 5 : 10;
}
int main() {
int arr[f<&a, &b>()] = {};
}
How should the storage for arr be allocated?
PLUS: This mechanism seems to be rather robust. Even when I enabled Randomized Base Address, the correct output is obtained.
The compiler doesn't need to know the value of &a at compile time any more than it needs the value of function addresses.
Think of it like this: the compiler will instantiate your function template with &a as a parameter and generate "object code" (in whatever format it uses to pass to the linker). The object code will look like (well it won't, but you get the idea):
func f__<funky_mangled_name_to_say_this_is_f_for_&a>__:
reg0 <- /* linker, pls put &std::cout here */
reg1 <- /* hey linker, stuff &a in there ok? */
call std::basic_stream::operator<<(int*) /* linker, fun addr please? */
[...]
If you instantiate f<b&>, assuming b is another global static, compiler does the same thing:
func f__<funky_mangled_name_to_say_this_is_f_for_&b>__:
reg0 <- /* linker, pls put &std::cout here */
reg1 <- /* hey linker, stuff &b in there ok? */
call std::basic_stream::operator<<(int*) /* linker, fun addr please? */
[...]
And when your code calls for calling either of those:
fun foo:
call f__<funky_mangled_name_to_say_this_is_f_for_&a>__
call f__<funky_mangled_name_to_say_this_is_f_for_&b>__
Which exact function to call is encoded in the mangled function name.
The generated code doesn't depend on the runtime value of &a or &b.
The compiler knows there will be such things at runtime (you told it so), that's all it needs. It'll let the linker fill in the blanks (or yell at you if you failed to deliver on your promise).
For your addition I'm afraid I'm not familiar enough about the constexpr rules, but the two compilers I have tell me that this function will be evaluated at runtime, which, according to them, makes the code non-conforming. (If they're wrong, then the answer above is, at least, incomplete.)
template <int* p, int* pp>
constexpr std::size_t f() {
return (p + 1) == (pp + 7) ? 5 : 10;
}
int main() {
int arr[f<&a, &b>()] = {};
}
clang 3.5 in C++14 standards conforming mode:
$ clang++ -std=c++14 -stdlib=libc++ t.cpp -pedantic
t.cpp:10:10: warning: variable length arrays are a C99 feature [-Wvla-extension]
int arr[f<&a, &b>()];
^
1 warning generated.
GCC g++ 5.1, same mode:
$ g++ -std=c++14 t.cpp -O3 -pedantic
t.cpp: In function 'int main()':
t.cpp:10:22: warning: ISO C++ forbids variable length array 'arr' [-Wvla]
int arr[f<&a, &b>()];
As far as I know, the variables of static storage and functions are stored simply as symbols/place holders in the symbol table while compiling. It is in the linking phase when the place holders are resolved.
The compiler outputs machine code keeping the placeholders intact. Then the linker replaces the placeholders of the variables / functions with their respective memory locations. So in this case too, if you just compile main.cpp without compiling a.cpp and linking with it, you are bound to face linker error, as you can see here http://codepad.org/QTdJCgle (I compiled main.cpp only)