what is wrong with the gcc internal symbol decoration? - c++

#include <stdio.h>
namespace myname{
double var = 42;
}
extern "C" double _ZN6myname3varE = 10.0;
int main(){
printf("%d\n", _ZN6myname3varE);
return 0;
}
The gcc compile result is:
Jim#ubuntu:~/workspace/vi_edit$ g++ testSymble.cpp -o testSymble
testSymble.cpp:7:19: warning: ‘_ZN6myname3varE’ initialized and declared ‘extern’ [enabled by default]
testSymble.cpp: In function ‘int main()’:
testSymble.cpp:10:32: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat]
/tmp/cczIjRfH.s: Assembler messages:
/tmp/cczIjRfH.s:14: Error: symbol `_ZN6myname3varE' is already defined
Why _ZN6myname3varE is redefined?
What does the warning ‘_ZN6myname3varE’ initialized and declared ‘extern’ [enabled by default] mean?
If the program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this clause, the behavior is undefined.
17.4.3.1.2 Global names
Each name that contains a double underscore (_ _) or begins with an underscore followed by an uppercase
letter (2.11) is reserved to the implementation for any use.

Why _ZN6myname3varE is redefined?
The C++ variable myname::var is name-mangled to _ZN6myname3varE by GCC. You've also defined a C (i.e. non-mangled) variable called _ZN6myname3varE. Therefore you have multiple definitions of the same symbol.
What does the warning [...] mean?
Standard usage is:
foo.h
extern "C" int myvariable;
foo.c/cc
#include "foo.h"
int myvariable = 42;
I'm not sure whether the C++ standard permits initialization of extern "C" variables (i.e. like you're doing). But the compiler is certainly warning you that what you're doing probably doesn't make sense.

The first warning message means that if you include extern in a variable's declaration, you cannot also include an initializer. Thus, both these lines generate that warning:
extern "C" int i = 9;
extern int j = 10;
You can either write:
int i = 9;
int j = 10;
or:
extern "C" int i;
extern int j;
or (as Adam Rosenfield points out in a comment), you can include braces in the line to allow an initializer:
extern "C" { int i = 9; }
Applied to your code, you cannot put the initializer = 42 in the extern "C" line, or you need to write:
extern "C" { double _ZN6myname3varE = 10.0; }
In isolation, and ignoring the final issue, that should 'work'.
The second warning means that namespace myname { double var = 42; } is a double so the %d conversion specification is wrong; it should be %f or %e or %g or variants on this theme.
printf("%f\n", myname::var);
The third message, the error, is from the assembler. Because the first message was only a warning, you actually have two different definitions which, when mangled, translate to _ZN6myname3varE, with two different initializers. You're only allowed one definition — the One Definition Rule.
However, names starting with an underscore followed by an upper-case letter are reserved for the implementation, so by trying to use the name _ZN6myname3varE directly, you are invoking undefined behaviour. Don't mess around with undefined behaviour; avoid it.

Related

C99 designator member outside of aggregate initializer

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;

Error facing with range function in DPC++

I'm new to Sycl/DPC++ language. I wrote a sample vector addition code using Unified shared memory (USM):
#include<CL/sycl.hpp>
#include<iostream>
#include<chrono>
using namespace sycl;
int main()
{
int n=100;
int i;
queue q{ };
range<1>(n);
int *a=malloc_shared<int>(n,q);
int *b=malloc_shared<int>(n,q);
int *c=malloc_shared<int>(n,q);
for(i=0;i<n;i++)
{
a[i]=i;
b[i]=n-i;
}
q.parallel_for(n,[=](auto &i){
c[i]=a[i]+b[i];
}).wait();
for(i=0;i<n;i++){
std::cout<<c[i]<<std::endl;
}
free(a,q);
free(b,q);
free(c,q);
return 0;
}
When I compile it I get the following error:
warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'n' [-Wvexing-parse]
range<1>(n);
^~~
vec_add.cpp:11:1: note: add enclosing parentheses to perform a function-style cast
range<1>(n);
^
( )
vec_add.cpp:11:9: note: remove parentheses to silence this warning
range<1>(n);
^ ~
vec_add.cpp:11:10: error: redefinition of 'n' with a different type: 'range<1>' vs 'int'
range<1>(n);
^
vec_add.cpp:8:5: note: previous definition is here
int n=100;
^
1 warning and 1 error generated.
How to fix this error?
error: redefinition of 'n' with a different type: 'range<1>' vs 'int'
Two variables with the same name within the same scope create confusion to the compiler, so it might be the reason for the error which you are getting. You can try defining the value of n globally say for eg: #define N 100 in this case, set
range<1>(n);
to
range<1> (N);
and use that in your code.
If you want to declare the size locally then assign another variable (r) to the range as
range<1> r (n);
Now you can directly pass the 'r' variable as a parameter to the parallel_for.

C++ error two or more data types in declaration of variable

I ran the following C program and got In as the output.
#include<stdio.h>
int main()
{
auto int i = 0;
if(++i)
printf("In");
else
printf("Out");
return 0;
}
But when I tried to run it as a C++ program by changing the header files and standard output, I got an error:
jdoodle.cpp: In function ‘int main()’:
jdoodle.cpp:6:14: error: two or more data types in declaration of ‘i'.
6 | auto int i = 0;
| ^.
jdoodle.cpp:7:10: error: ‘i’ was not declared in this scope.
7 | if(++i).
| ^
C++ code:
#include <iostream>
using namespace std;
int main() {
auto int i = 0;
if(++i)
cout<<"In";
else
cout<<"Out";
return 0;
}
In C, auto is an obsolete keyword it inherited from B. It is either implicitly assumed, or illegal to specify. So, it's basically never used.
C++ inherited this keyword from C as is, and your code would have compiled under C++98. In C++11 this keyword was repurposed to be used for implicit type deduction. It is now widely used but means something completely different and the way you tried to use it is illegal.
The point is, C and C++ are different languages. Writing code that compiles under C and C++ is difficult and requires care.
In the C++ program, for the line
auto int i = 0;
the auto keyword is being used to automatically deduce the type of variable i from its initialized value if compiling with C++11 or later. However, the line also includes int, which is also declaring the type. You can't use both of them -- you get the same error if you write double int i = 0; (i can't be both a double and an int) or int int i = 0; (it's the same type but you're declaring the type twice). Choose one or the other, i.e. either
auto i = 0;
or
int i = 0;
You can see that it works with C++98 but not C++11 or C++14 online here. Prior to C++11 the auto keyword was a storage class specifier.

Why do C++ deprecated warnings print twice?

If I have
namespace foo {
inline int bar() {
return 1119;
}
}
__attribute__((deprecated)) inline int bar() {
return 138;
}
in header.h and
#include "header.h"
#include <iostream>
int main() {
int x = bar();
int y = foo::bar();
std::cout << x << std::endl;
std::cout << y << std::endl;
}
in source.cpp, then
g++ source.cpp -o deprecated-test
results in
source.cpp: In function ‘int main()’:
source.cpp:5:17: warning: ‘int bar()’ is deprecated [-Wdeprecated-declarations]
int x = bar();
^
In file included from source.cpp:1:
header.h:7:40: note: declared here
__attribute__((deprecated)) int bar() {
^~~
source.cpp:5:17: warning: ‘int bar()’ is deprecated [-Wdeprecated-declarations]
int x = bar();
^
In file included from source.cpp:1:
header.h:7:40: note: declared here
__attribute__((deprecated)) int bar() {
(on Ubuntu 18.10 with g++ 8.2.0).
Why does the deprecated warning print twice?
Heading off some suggestions that would be unhelpful:
[[deprecated]]:
I know with C++14 on you can use the [[deprecated]] attribute, but I need to work with C++11.
Declaration vs. definition: The docs seem to imply it should be used with function declaration rather than definition, but
I need to define the functions inline in a header rather than declare in the header and define in source files; and
Trying this approach didn't stop the warning from printing twice anyway.
As per the documentation of GCC 8.2.0:
The deprecated attribute results in a warning if the function is used anywhere
in the source file. This is useful when identifying functions that are expected
to be removed in a future version of a program. The warning also includes the
location of the declaration of the deprecated function, to enable users to easily
find further information about why the function is deprecated, or what they
should do instead. Note that the warnings only occurs for uses...
There should be only one warning and not two. So this is a bug in GCC.
There is a related bug for Type attributes (rather than Function attributes) titled: C/C++ __attribute__((deprecated)) does not appear to wrap declarations as implied from the doc.
It has been confirmed as a bug.

Is clang++ ignoring extern "C" for some deprecation warnings?

If I use clang 3.8.1 to compile:
extern "C" {
int foo(int x) { register int y = x; return y; }
}
int main() { return foo(123); }
I get the warning:
a.cpp:3:18: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
int foo(int x) { register int y = x; return y; }
^~~~~~~~~
... which I really shouldn't be getting this, since the inner function is C code. If I use GCC 6.3.1, even with -Wall, I don't get this warning.
Is this a clang bug or am I doing something wrong?
extern "C" does not mean "compile this code as C". It means "make this function (or functions) callable from C code", which typically means changing name mangling and, sometimes, calling convention.
Perhaps the error has nothing to do with the extern "C"? It looks like it says, not, "register is incompatible with C" but rather "register is incompatible with C++1z". (I assume C++1x means C++11/14/17.)