sizeof struct or variable in C and C++ - c++

I can't understand why this code prints 1 in C, but other digit in C++?
#include <stdio.h>
static char T = 'a';
int main(int argc, char** argv) {
struct T { char X[2]; };
printf("size of T is %zu\n", sizeof(T));
}
And why this code prints 1 in both C and C++?
#include <stdio.h>
int main(int argc, char** argv) {
static char T = 'a';
struct T { char X[2]; };
printf("size of T is %zu\n", sizeof(T));
}
Can somebody explain me this a little bit, please?

Because in C the struct is called struct T and not only T. In C++ the local definition of struct T will hide the global variable T:
#include <stdio.h>
static char T = 'a'; // (1)
int main(int argc, char** argv) {
// `struct T` shadows outer `T` in C++
struct T { char X[2]; }; // (2)
// C: sizeof char (1); C++: sizeof struct T (2)
printf("size of T is %u\n", sizeof(T));
// C/C++: sizeof struct T (2)
printf("size of struct T is %u\n", sizeof(struct T));
}
On the other hand, when both declarations are in the same naming context, the ambiguity of the identifier T will result in the same results, since C++ expects you to specify that you really want to use the struct and not the char T:
#include <stdio.h>
int main(int argc, char** argv) {
static char T = 'a';
struct T { char X[2]; };
printf("size of T is %u\n", sizeof(T)); // sizeof (char)
printf("size of struct T is %u\n", sizeof(struct T));// sizeof struct T
}
Which results in the same size for both C and C++.
How to avoid this mistakes
Usually compilers do know that the identifier is ambiguous, but the warning is often hidden. Use compiler flags to show warnings, in GCC -Wall -Wextra are the most useful for usual programming:
test.cc: In function »int main(int, char**)«:
test.cc:5:43: Warning: unknown converting symbol »z« in format [-Wformat]
test.cc:5:43: Warning: to many arguments for format [-Wformat-extra-args]
test.cc: global:
test.cc:3:5: Warning: unused parameter »argc« [-Wunused-parameter]
test.cc:3:5: Warning: unused parameter »argv« [-Wunused-parameter]
test.cc:2:13: Warning: »T« defined, but not used [-Wunused-variable]
In this case one will see that the global static char T has been defined, but never used.

In C, when a structure is declared, it is of type struct <name of struct> and not just the name of the struct. That is the reason. To avoid confusion, people use typedef to simplify the declarations in C

As mentioned by others, in the first snippet the local struct T will hide the static var in C++. However, to fully understand what's going on, you also have to talk about name disambiguation. In the second code snippet, struct T isn't hiding T - they're in the same scope.

Related

Error obtaining parameters of a structure pointer in c ++

I have defined the following structure:
struct com_NetworkStruct
{
enum com_NetworkStatus status;
char IPV4_Addr[COM_IPV4_ADDR_LENGTH];
char IPV4_Netmask[COM_IPV4_ADDR_LENGTH];
char IPV4_DNS1[COM_IPV4_ADDR_LENGTH];
char IPV4_DNS2[COM_IPV4_ADDR_LENGTH];
int IPV4_DHCP_Enabled;
int IPV6_Supported;
int IPV6_Enabled;
struct com_IPv6_Data *IPV6_Address_List;
char HW_Addr[COM_ETH_MAC_ADDR_LENGTH];
int MTU_Size;
int Link_Speed;
enum com_LinkType Link_Type;
};
And the following method definition:
int foo(struct com_NetworkStruct **netinfo);
This is the main function and how i call the function:
int main(int argc, char const *argv[])
{
int ret;
char data_aux[200];
struct com_NetworkStruct *netinfo = NULL;
ret = foo(&netinfo);
memset(data_aux, 0, sizeof(data_aux));
sprintf(data_aux, "%s", netinfo->IPV4_Addr);
cout<<string(data_aux)<<endl;
return 0;
}
The problem is when I try to read the data of the IPV4_Addr value since it sends me the following error:
Error: #289: no instance of constructor "std::basic_string<_CharT, Traits, Alloc>::basic_string [with CharT=char, Traits=std::char_traits<char>, _Alloc=std::allocator<char>]" matches the argument list
argument types are: (const char [20], char [16])
I already tried this, but nothing works:
&netinfo->IPV4_Addr
netinfo.IPV4_Addr
string(netinfo->IPV4_Addr)

How to initialize a struct with union?

How can I properly initialize a struct which contains a union? Currently I get an error // error C2440: 'initializing': cannot convert from 'float' to 'const char *'
#include <stdio.h>
using namespace std;
typedef enum {STRING, REAL, POINTER } Type;
const struct Entry {
union {
const char *string;
float real;
void *pointer;
};
Type type;
LPCSTR Key;
LPCSTR Name;
}f;
const Entry Entries[] = {
{{0.5f}, REAL, "Key", "Name" } // error C2440: 'initializing': cannot convert from 'float' to 'const char *'
};
int main(int argc, char **argv)
{
for (int i = 0; i < size(Entries); i++)
{
switch Entries[i].type
{
case STRING:
printf("Type string; Value: %s\n", Entries[i].string);
case REAL:
printf("Type string; Value: %d\n", Entries[i].real);
}
}
}
When initializing a union, only the first member will be initialized. Rearrange the union so that float real becomes the first member of the union.
Of course, that means you can't use the other members in direct initialization.
The other solution is to add a constructor to the union, like one for the real member, one for the string member and one for the pointer member.
What is the reason You want to use union? Unions are great for saving memory. In c++ rarely there is a need to use them.
I know that is not the answer for your question but think if You have to use them in this project.

what does a const char** look like?

I have a class which takes the main command line arguments (eg, -B, -a, etc) and does something with them, but also i would like to be able to instantiate that function without passing the command line arguments, so for example:
constructor:
myClass(int argc, const char **argv){
<initialise class with flags from argv>
}
myClass() : myClass(2, "-B") {}
}
Here i am trying to instantiate myClass with the flag "-B", but it keeps giving me the error:
no known conversion for argument 3 from ‘const char [3]’ to ‘const char**’
so i was wondering what i need to do to pass a value in as const char**?
First level is pointer to first pointer to char *. Second level is pointer to the first const char of c-string.
> cdecl explain "const char ** args"
declare args as pointer to pointer to const char
If you have -std=c++11 available, you can use this example (but it can be rewritten to use old standard):
#include <iostream>
#include <vector>
#include <string>
class test {
public:
test(const std::vector<std::string> & args) {
for (auto & arg : args) {
std::cout << arg << "\n";
}
}
test() : test{{"-B"}} {}
};
int main(int argc, const char ** argv) {
test sth{{argv+1, argc+argv}}; // skip program name here
test sth_else;
}
const char** is pointer to const char*. In your case, you intend to pass multiple arguments as part of argv, so you can pass something like below:
const char* argv[] = {"<program name>", "B"};
myClass m(2, argv);
Note: const char** x & const char* x[] are same. The 2nd syntax is helpful when one wants to "represent" an array.
Here I am giving a way to mimic the main(int, char**) function argument for your internal test. If you want to pass from default constructor to argument constructor then all the above stuff will have to go global.

What does the 'hides constructor for' warning mean when compiling C++ with g++?

Using the following code:
#include <stdio.h>
struct my_struct {
int a;
int b;
my_struct();
};
my_struct::my_struct(void)
{
printf("constructor\n");
}
void my_struct(void)
{
printf("standard function\n");
}
int main (int argc, char *argv[])
{
struct my_struct s;
s.a = 1;
s.b = 2;
printf("%d-%d\n", s.a, s.b);
return 0;
}
I get a warning compiling with g++ -Wshadow main.cpp:
main.cpp:15:20: warning: ‘void my_struct()’ hides constructor for ‘struct my_struct’
I would be ok with that warning if the void my_struct function actually replaced the my_struct::my_struct one. But it does not appears to be the case. If I run the program, I get:
constructor
1-2
Any idea what this warning mean ? It is quite annoying especially when I include C headers into C++ code
The warning points out that the my_struct() function has the same name as the my_struct structure. It means you will be unable to write:
my_struct s; // Error.
Because the compiler will think that you're using a function as a type. However, as you probably realized, you can still instantiate your structure with the struct keyword:
struct my_struct s; // Valid.
void my_struct(void) has the same name of your class/struct and since it is in the global namespace it is conflicting with your class/struct's constructor.
You could try something like:
#include <cstdio>
struct my_struct {
int a;
int b;
my_struct();
};
my_struct::my_struct(void)
{
printf("constructor\n");
}
namespace mbonnin
{
void my_struct(void);
}
void mbonnin::my_struct(void)
{
printf("standard function\n");
}
int main (int argc, char *argv[])
{
my_struct s;
s.a = 1;
s.b = 2;
printf("%d-%d\n", s.a, s.b);
mbonnin::my_struct();
return 0;
}
And by the way the struct in struct my_struct s; is redundant in C++.
warning: ‘void my_struct()’ hides constructor for ‘struct my_struct’
Any idea what this warning mean ?
It means that sometimes the warnings issued by the GNU compiler suite are a bit off. (Try omitting the semicolon after the close brace on the definition of struct my_struct. If you are using anything but a very recent version of g++ the error message will be a bit off.)
Something is being hidden here, but it is not the constructor for struct my_struct. What is being hidden is the name my_struct as a type identifier. You can see this in action if you remove the struct from the declaration of the variable s: Use my_struct s; instead of struct my_struct s; Without the contextual information offered by the struct keyword, the compiler now must interpret my_struct as a function name.

How do you make C++ create an expression that uses compile-time checking for constants and asserts for variables?

Here’s an example setup… a macro or a template CHECKEXPR_RETURNVAL(EXPR,VAL) that checks that EXPR is TRUE while returning VAL.
This is useful in a variety of places -- like in this highly simplified example:
#define ISPOW2(VAL) ((0!=VAL)&&(0==(VAL&(VAL-1))))
#define _ALIGNPOW2(VAL,ALIGN) ((VAL+(ALIGN-1))&(~(ALIGN-1)))
#define ALIGNPOW2(VAL,ALIGN) CHECKEXPR_RETURNVAL( \
ISPOW2(ALIGN) , _ALIGNPOW2(VAL,ALIGN) )
So, the difficulty is this: I want to do compile time checks if possible, and if the value is not a constant that is determinate at compile time, then do a runtime check.
Basically, the idea is to catch bad parameters as soon as possible; if you can catch a bad parameter at compile time that's better than finding out at run time. Also, the compile time version is required for constant initializers.
Here are my two (failed) attempts to make single version work in multiple places (as a constant array size, as an enum initializer, and in a function with variables). Unfortunately, they either work for the compile time only (constant initializer) or the runtime only -- I would like to figure out a version that will work for both.
// CHECKEXPR_RETURNVAL - version "A"
#define CTCHECK_EXPR(EXP)(CTCheckBool<EXP>::ExistsZeroIfTrue)
template <bool bExpression> struct CTCheckBool {};
template <> struct CTCheckBool<true> {enum{ExistsZeroIfTrue=0};};
// Note: Plus ("+") is used rather than comma operator because
// the comma operator can not be used for constant initializers
#define CHECKEXPR_RETURNVAL_A(EXP,VAL) (CTCHECK_EXPR(EXP) + (VAL))
// Test Out version "A" -- works only for Compile Time Constants
#define ALIGNPOW2_A(VAL,ALIGN) CHECKEXPR_RETURNVAL_A( \
ISPOW2(ALIGN) , _ALIGNPOW2(VAL,ALIGN) )
char AlignedVar_A[ALIGNPOW2_A(2,8)];
enum { AlignedVal_A = ALIGNPOW2_A(57,16) };
int TestAlignPow2_A(int val, int align)
{return(ALIGNPOW2_A(val,align));} // Compile Error
// CHECKEXPR_RETURNVAL - version "B"
template<typename T> T CHECKEXPR_RETURNVAL_B(bool bExpr,T val)
{ ASSERT(bExpr); return(val); }
// Test Out version "B" -- works only for Runtime Computed Values
#define ALIGNPOW2_B(VAL,ALIGN) CHECKEXPR_RETURNVAL_B( \
ISPOW2(ALIGN) , _ALIGNPOW2(VAL,ALIGN) )
char AlignedVar_B[ALIGNPOW2_B(2,8)]; // Compile Error
enum { AlignedVal_B = ALIGNPOW2_B(57,16) }; // Compile Error
int TestAlignPow2_B(int val, int align)
{return(ALIGNPOW2_B(val,align));}
Unfortunately, neither version works for all three cases. Is there a code structure that will work for all the cases ?
It seems like you would really make use of c++0x constexpr functions...
Well... Not a complete answer, but I think you can derive what you want from this:
#include <stdio.h>
template <int I> struct S{
static void doIt(){
fprintf(stderr, "wow\n");
}
};
template<> void S<0>::doIt(){
fprintf(stderr, "oops\n");
}
#define EXPR(p) S<(int)((bool)(p))>::doIt()
int main(int argc, char** argv){
EXPR((5+2)==7);
EXPR((5+2)==8);
const int a = 58;
EXPR(a==58);
EXPR(58);
return 0;
}
You can get a compiler error based on expression:
#include <stdio.h>
template <int I> struct S{
static void doIt(){
ssdfkjehiu //deliberately invalid code
fprintf(stderr, "oops\n");
}
};
template<> void S<1>::doIt(){
fprintf(stderr, "wow\n");
}
#define EXPR(p) S<(int)((bool)(p))>::doIt()
int main(int argc, char** argv){
EXPR((5+2)==7);
EXPR((5+2)==8);//uncomment it to make code compile
const int a = 58;
EXPR(a==58);
EXPR(58);
return 0;
}
But the line that causes error will be in a middle of a lengthy template error message. Example:
1.cpp(6) : error C2065: 'asdlfkjhasd' : undeclared identifier
1.cpp(4) : while compiling class template member function 'void S<I>::doIt(void)'
with
[
I=0
]
1.cpp(19) : see reference to class template instantiation 'S<I>' being compiled
with
[
I=0
]
1.cpp(6) : error C2146: syntax error : missing ';' before identifier 'fprintf'
As you see, error is caused by line 19, which is mentioned in the middle of the message. This is a bit inconvenient.
I cannot guarantee that both examples doesn't rely on some undefined C++ behavior.
Also, I think that the next code maintainer may not be happy about this...
P.S. I think you should also take a look at boost. If I remember correctly, it had quite a lot of "magic preprocessor macro" (loops, for example), so it is possible that it implemented something similar.
--edit--
Okay, what about this one?:
#include <stdio.h>
#include <string>
template <typename T> void a(T &i){
fprintf(stderr, "variable\n");
}
void a(const char* const i){
fprintf(stderr, "constant\n");
}
void a(bool i){
fprintf(stderr, "constant\n");
}
int main(int argc, char** argv){
int i;
float f;
std::string s;
const char* s1 = "b";
a(3);
a(3+2);
a(1.0f);
a('a');
a("b");
a(i);
a(f);
a(s);
a(s1);
return 0;
}