Iterable Designated Initializer Alternative in C++ - c++

In C99, a struct array can be initialized
static struct {char* tag; char* msg;} help_info[] = {[0]={"tag0","msg0"}, [1]={"tag1", "msg1"}};
This is not valid in C++. What is a possible alternative to replicate this behavior for an iterable object containing defined information?

C++20 added designated initializers to C++. There are some restrictions compared to C, in a couple of different directions. In your case, the main difference of note is that C++ has tightened up a bit of the type system so you can no longer initialize a char * from a string literal.
In C, you can initialize a char * from a string literal for the sake of backward compatibility, but you still have to treat it as if it were a char const *--that is, if you try to write to the string literal you get undefined behavior (and on a modern machine, you'll typically get something on the order of a seg fault that will kill your program).
C++ now demands that you recognize that limitation by using char const * explicitly. If we change your code to suit:
static struct {char const* tag; char const* msg;} help_info[] =
{[0]={"tag0","msg0"}, [1]={"tag1", "msg1"}};
...and compile it as C++, it's perfectly fine.
Do note there are other limitations that don't exist in C (but they don't affect this code). For example, C++ demands that the initializers be in order, so in C you also do this:
static struct {char const* tag; char const* msg;} help_info[] =
{[1]={"tag1", "msg1"}, [0]={"tag0","msg0"}};
...so the initializer for [1] precedes the initializer for [0], but in C++ that's forbidden.

As stated in another answer:
From this link designated-initializer not supported in C++ Designated Initializers:
Note: out-of-order designated initialization, nested designated initialization, mixing of designated initializers and regular initializers, and designated initialization of arrays are all supported in the C programming language, but are not allowed in C++.
However, I believe this code will meet your need.
static struct { const char* tag; const char* msg; } help_info[] = { {"tag0","msg0"}, {"tag1", "msg1"} };

From this link designated-initializer not supported in C++ :
Note: out-of-order designated initialization, nested designated
initialization, mixing of designated initializers and regular
initializers, and designated initialization of arrays are all
supported in the C programming language, but are not allowed in C++.
I think, it is not possible.

Related

return {0} from a function in C?

I got the following discrepancy between compiling as 'C' vs. compiling as 'C++'
struct A {
int x;
int y;
};
struct A get() {
return {0};
}
When compiling as 'C++' everything goes fine.
However, when compiling as 'C'; i am getting:
error : expected expression
which i can fix by doing:
return (struct A){0};
However, i wonder where the difference comes from. Can any one point in the language reference where this difference comes from?
The two use completely different mechanisms, one of which is C++11-specific, the other of which is C99-specific.
The first bit,
struct A get() {
return {0};
}
depends on [stmt.return] (6.6.3 (2)) in C++11, which says
(...) A return statement with a braced-init-list initializes the object or reference to be returned from the function by copy-list-initialization from the specified initializer list. [ Example:
std::pair<std::string,int> f(const char *p, int x) {
return {p,x};
}
-- end example ]
This passage does not exist in C (nor C++ before C++11), so the C compiler cannot handle it.
On the other hand,
struct A get() {
return (struct A){0};
}
uses a C99 feature called "compound literals" that does not exist in C++ (although some C++ compilers, notably gcc, provide it as a language extension; gcc warns about it with -pedantic). The semantics are described in detail in section 6.5.2.5 of the C99 standard; the money quote is
4 A postfix expression that consists of a parenthesized type name followed by a brace-enclosed list of initializers is a compound literal. It provides an unnamed object whose value is given by the initializer list. (footnote 80)
80) Note that this differs from a cast expression. For example, a cast specifies a conversion to scalar types or void only, and the result of a cast expression is not an lvalue.
So in this case (struct A){0} is an unnamed object that is copied into the return value and returned. (note that modern compilers will elide this copy, so you do not have to fear runtime overhead from it)
And there you have it, chapters and verses. Why these features exist the way they do in their respective languages may prove to be a fascinating discussion, but I fear that it is difficult for anyone outside the respective standardization committees to give an authoritative answer to the question. Both features were introduced after C and C++ split ways, and they're not developed side by side (nor would it make sense to do so). Divergence is inevitable even in small things.

Designated Initializers in C99: How to handle empty uninitialized struct members in C11?

Since in C I can call the members of a struct by name (myStruct.myMember = ) I was wondering what I would do in C++ with those members that are not initialized.
So as I understood, C++ does not support this kind of initialization:
static struct usb_endpoint_descriptor fs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16 (64),
};
But when I use correct syntax, how do I handle members that are not initialized?
Let's say I want bDescriptorType uninitialized. Do I set it to NULL?
static struct usb_endpoint_descriptor fs_source_desc = {
USB_DT_ENDPOINT_SIZE,
NULL,
USB_ENDPOINT_XFER_BULK,
__constant_cpu_to_le16 (64)
};
Or is there any way in C++ to initialize the structure's members by their name?
how do I handle members that are not initialized?
The feature you describe is called designated initializers and was introduced in C99. It is not supported by C++. All members that are not initialized explicitly are guaranteed to be set to zero (*).
Maybe you didn't consider it, but the same applies to regular struct initialization as well. Example:
typedef struct
{
int a;
int b;
} ab;
ab mystruct = { .a = 1 }; // a is 1, b is guaranteed to be 0
ab mystruct = { 1 }; // a is 1, b is guaranteed to be 0
(The last example is also true for C++.)
This language rule is the reason why we can initialize all elements in a struct/array to zero by typing:
ab mystruct = { 0 };
because it actually means "set a to zero, and let then all other elements be implicitly initialized to zero".
(*) Formally, they are initialized as if they had static storage duration, i.e. data gets set to zero, pointers get set to NULL etc. C11 6.7.9/10.
If you use C++, then use constructors. Init by NULL is more C-way really.
And no, there is no standard C++ way to use named parameters (something like boost::parameters may help, but there is no need to it here).
Your case may be something like
struct usb_endpoint_descriptor
{
usb_endpoint_desctiptor(type bL, type bAttr, type wSize) :
bLength(bL), bAttributes(bAttr), wMaxPacketSize(wSize) {}
type bLength;
type bDescriptorType;
type bmAttributes;
type wMaxPacketSize;
};
However, it's bad style to leave variables not-initialized in C++.
So, if you use C structure, you can
1) Write C++ wrapper.
2) Write derived class.
3) Initialize field, that you don't want to initialize with some default value.
FYI, All of the previous answers were correct. there was no support for designated initializers in C++... until C++20.
C++20 added aggregate initializers in that version of the C++ standard.
The syntax is different than C99 dot notation because, I guess the standard committee wanted the syntax to be more idiomatically Cplusplussesque.
Here is an on point stack overflow question
Designated initializers in C++20
And here is a popular reference site. https://en.cppreference.com/w/cpp/language/aggregate_initialization

Is there const in C?

This question may be naive, but:
is there const keyword in C?
since which version?
are there any semantic and/or syntactic differences between const in C and C++?
There are no syntactic differences between C and C++ with regard to const keyword, besides a rather obscure one: in C (since C99) you can declare function parameters as
void foo(int a[const]);
which is equivalent to
void foo(int *const a);
declaration. C++ does not support such syntax.
Semantic differences exist as well. As #Ben Voigt already noted, in C const declarations do not produce constant expressions, i.e. in C you can't use a const int object in a case label, as a bit-field width or as array size in a non-VLA array declaration (all this is possible in C++). Also, const objects have external linkage by default in C (internal linkage in C++).
There's at least one more semantic difference, which Ben did not mention. Const-correctness rules of C++ language support the following standard conversion
int **pp = 0;
const int *const *cpp = pp; // OK in C++
int ***ppp = 0;
int *const *const *cppp = ppp; // OK in C++
These initializations are illegal in C.
int **pp = 0;
const int *const *cpp = pp; /* ERROR in C */
int ***ppp = 0;
int *const *const *cppp = ppp; /* ERROR in C */
Generally, when dealing with multi-level pointers, C++ says that you can add const-qualification at any depth of indirection, as long as you also add const-qualification all the way to the top level.
In C you can only add const-qualification to the type pointed by the top-level pointer, but no deeper.
int **pp = 0;
int *const *cpp = pp; /* OK in C */
int ***ppp = 0;
int **const *cppp = ppp; /* OK in C */
Another manifestation of the same underlying general principle is the way const-correctness rules work with arrays in C and C++. In C++ you can do
int a[10];
const int (*p)[10] = &a; // OK in C++
Trying to do the same in C will result in an error
int a[10];
const int (*p)[10] = &a; /* ERROR in C */
The first two questions are answered here: Const in C
Yes there are quite a few differences in semantics between const in C and C++.
In C++, const variables of appropriate type are integral constant expressions (if their initializers are compile-time constant expressions) and can be used in context which requires that, such as array bounds, and in enum definitions. In C, they are not and cannot be.
In C++, const global variables automatically have static linkage, so you can put them in header files. In C, such variables have external linkage and that would generate duplicate definition errors at link time.
Yes, there is a const keyword. It was added as part of the 1989 standard.
As far as compatibility, here's a paragraph from Harbison & Steele, 5th edition:
A top-level declaration that has the type qualifier const but no explicit storage class is considered to be static in C++ but extern in C. To remain compatible, examine top-level const declarations and provide an explicit storage class.
In C++, string constants are implicitly const; they are not in C.
Yes, const has been there since at least since ANSI C (aka C89).
It certainly appears in my copy of "The C Programming Language (2nd Edition)", Kernighan & Ritchie (published in 1988).
Relevant extract:
The const and volatile properties are new with the ANSI standard. The purpose of const is to
announce objects that may be placed in read-only memory, and perhaps to increase opportunities for
optimization.
Two other differences:
const arraytype (i.e typedef int A[1]; const A a = { 0 };) specifies a constant array type ( http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#112 and http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1059 ) (and whose elements are so-qualified too) in C++, but a non-constant array type whose elements are so-qualified in C.
const const is valid in C99 (not valid in C89), not valid in C++ in any version (you can only semantically repeat a const, not syntactically). It contracts to const in C99.
Yes. const is there in C, from C89.
Here is a good read is about behaviour of const keyword in C.
The semantic in C is different than in C++. For example,
unsigned const a = 10;
unsigned A[a];
in file scope would be valid in C++, but not in C.
Yes, there's a const keyword in C. It's been there since C90.
Syntactically, it can occur in the same places as in C++. Semantically, it's a bit more lax, IIRC.
According to ESR, const was added in the ANSI C Draft Proposed Standard. Eric Giguere's summary of ANSI C, dated 1987, confirms it.
This looks like the draft itself -- search for "3.5.3 Type qualifiers".
There is a "const" keyword in C, and it has been for a long time. If a variable is designated "const", writes to it are forbidden.
Additionally, in some environments, variables declared "const" may be located in a different data segment from other variables. This data segment may offer hardware write protection, and for embedded systems, may be stored in ROM or flash memory rather than in RAM (a very important distinction on some processors which have a lot more ROM or flash than RAM--e.g. 128 KB flash and 3.5 KB RAM, or 2 KB ROM and 96 bytes RAM).
Note that the compiler will generally not make any inferences about "const" values or expressions involving them. If I say "const char foo[] = "Hello";" and then later make reference to foo[1], the compiler will load the value (which will most likely be 'e') from wherever foo[] is stored and use the loaded value. Sometimes this usefully allows values to be patched in a compiled code image, but sometimes it just wastes code.
If you want to define a number to to be a compile-time "substitutable" constant, the best way, at least for integer constants, may be to use "enum". For example, "enum {woozle=19;}" will cause 19 to be substituted for "woozle" throughout the code. Note that unlike textual substitutions; enum declarations obey proper rules of scope.

Explicit initialization of struct/class members

struct some_struct{
int a;
};
some_struct n = {};
n.a will be 0 after this;
I know this braces form of initialization is inherited from C and is supported for compatibility with C programs, but this only compiles with C++, not with the C compiler. I'm using Visual C++ 2005.
In C this type of initialization
struct some_struct n = {0};
is correct and will zero-initialize all members of a structure.
Is the empty pair of braces form of initialization standard? I first saw this form of initialization in a WinAPI tutorial from msdn.
The empty braces form of initialization is standard in C++ (it's permitted explicitly by the grammar). See C Static Array Initialization - how verbose do I need to be? for more details if you're interested.
I assume that it was added to C++ because it might not be appropriate for a 0 value to be used for a default init value in all situations.
It is standard in C++, it isn't in C.
The syntax was introduced to C++, because some objects can't be initialized with 0, and there would be no generic way to perform value-initialization of arrays.
The {0} is C99 apparently.
Another way to initialize in a C89 and C++ compliant way is this "trick":
struct some_struct{
int a;
};
static some_struct zstruct;
some_struct n = zstruct;
This uses the fact that static variables are pre-initialized with 0'ed memory, contrary to declarations on the stack or heap.
I find the following link to be very informative on this particular issue
http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/strin.htm

using a static const int in a struct/class

struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
return A::B::b;
}
The above code compiles. However if you go by Effective C++ book by Scott Myers(pg 14);
We need a definition for a in addition to the declaration.
Can anyone explain why this is an exception?
C++ compilers allow static const integers (and integers only) to have their value specified at the location they are declared. This is because the variable is essentially not needed, and lives only in the code (it is typically compiled out).
Other variable types (such as static const char*) cannot typically be defined where they are declared, and require a separate definition.
For a tiny bit more explanation, realize that accessing a global variable typically requires making an address reference in the lower-level code. But your global variable is an integer whose size is this typically around the size of an address, and the compiler realizes it will never change, so why bother adding the pointer abstraction?
By really pedantic rules, yes, your code needs a definition for that static integer.
But by practical rules, and what all compilers implement because that's how the rules of C++03 are intended - no, you don't need a definition.
The rules for such static constant integers are intended to allow you to omit the definition if the integer is used only in such situations where a value is immediately read, and if the static member can be used in constant expressions.
In your return statement, the value of the member is immediately read, so you can omit the definition of the static constant integer member if that's the only use of it. The following situation needs a definition, however:
struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
int *p = &A::B::b;
}
No value is read here - but instead the address of it is taken. Therefore, the intent of the C++03 Standard is that you have to provide a definition for the member like the following in some implementation file.
const int A::B::b;
Note that the actual rules appearing in the C++03 Standard says that a definition is not required only where the variable is used where a constant expression is required. That rule, however, if strictly applied, is too strict. It would only allow you to omit a definition for situation like array-dimensions - but would require a definition in cases like a return statement. The corresponding defect report is here.
The wording of C++0x has been updated to include that defect report resolution, and to allow your code as written.
However, if you try the ternary operand without "defining" static consts, you get a linker error in GCC 4x:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13795
So, although constructs like int k = A::CONSTVAL; are illegal in the current standard, they are supported. But the ternary operand is not. Some operators are more equal than others, if you get my drift :)
So much for "lax" rules. I suggest you write code conforming to the standard if you do not want surprises.
In general, most (and recent) C++ compilers allow static const ints
You just lucky, perhaps not. Try older compiler, such as gcc 2.0 and it will vehemently punish you with-less-than-pretty error message.