Using lambda captured constexpr value as an array dimension - arrays

GCC and Clang do compile the following code:
void Test()
{
constexpr int Size = 3;
auto Lambda = [Size]{ int Dim[Size]; };
}
However, VisualStudio 2015 CTP 6 does not. Nevertheless, all 3 compilers are happy with this code:
void Test()
{
static constexpr int Size = 3;
auto Lambda = []{ int Dim[Size]; };
}
Which snippet is actually doing it in the correct way? What does the C++ standard say?
This question is related to Lambda capturing constexpr object

C++11 [expr.prim.lambda]/12
If a lambda-expression odr-uses this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression.
and /17
Every id-expression that is an odr-use of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type. [ Note: An id-expression that is not an odr-use
refers to the original entity, never to a member of the closure type. [...]
— end note ]
So we don't even need to capture Size in the first example (where it is not static), since reading from that variable is not an odr-use since it can appear in a constant expression and the lvalue-to-rvalue conversion is immediately applied to it, [basic.def.odr]/2
A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression and the lvalue-to-rvalue
conversion is immediately applied.
(It is not clear to me if the array bounds require an l-t-r conversion, though.)
The same applies when capturing Size by reference, or when capturing Size explicitly (by copy) but not odr-using it: the use of the id-expression Size within the lambda accesses the constexpr variable declared in Test, not any captured member (for capture-by-copy: IFF the access does not constitute an odr-use).
C++14 [expr.prim.lamda]/12 adds some wording for polymorphic lambdas that is irrelevant here, and moves /17 to /18. The rules for odr-use are more complicated, but I'd argue it's not an odr-use for the same underlying reason (reading a compile-time constant).

Related

Need clarification of the meaning of "side effect" in C

I have read many discussions of what constitutes a "side effect" in C, and many seem to indicate that it must involve changing something that is not local to the function causing the change. Changing an external variable or a file are the typical types of things the discussions say have to be changed to qualify as a side effect. The discussions also commonly imply that merely changing the value of a local automatic variable in the same block in which it is declared is not a side effect. However, 5.1.2.3.2 of the C17 standard states the following:
Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects,12) which are changes in the state of the execution environment.
My understanding from C17 6.2.4.1 is that all variables (among other things) represent objects. If that is the case, wouldn't changing the value of any variable regardless of scope or storage class qualify as a side effect?
If that is the case, wouldn't changing the value of any variable regardless of scope or storage class qualify as a side effect?
Yes.
Consider the code a = 3; printf("%d\n", a++);. This prints “3”, because the main effect of a++ is to produce the value of a for the expression, and the value of a is 3. The code also changes the value of a, and that is a side effect.
Consider printf("%d\n", (a = 3) * 4);. The main effect of the assignment expression, a = 3, is to produce the new value of the assigned object, so its value is 3. Then that is multiplied by 4, so printf prints “12”. As a side effect, the stored value of a is changed to 3.
Also, printf writes to standard output, and that is also a side effect.

Declaring struct instances as static/local in main() with while(1)

I am working on microntroller RZA1, with KPIT GNUARM 16 toolchain, in e2 studio. I am not an expert on the subject, so I'll try to explain the problem the best that I can. The issue is related to a structure mainwindow, defined in my code, which contains important features of the graphical interface:
typedef struct
{
page_t pages[MAXNUMPAGE];
logger_t storico;
messagges_t messaggio;
graph_t grafico;
} mainwindow_t;
In the main() function I declare a local instance of this struct, as it contains a while(1) loop, which is used to refresh the GUI application in case of user interaction (i.e pushbutton clicked). The problem that I have encountered is that there's a difference in the way program executes in case the instance of mainwindow_t is declared with or without static keyword. For instance,
main()
{
static mainwindow_t mainwindow;
....
init_pages(mainwindow.pages);
while(1)
{
page_update(mainwindow.pages);
}
}
works perfectly well, whereas with only mainwindow_t mainwindow; it seems that the changes made in the function init_pages() had no effect: entire content of the array page[MAXNUMPAGE] is uninitialized.
Therefore, my question is: should there be any functional difference between non-static local and static local declaration of an array inside a function, if that function basically never returns ?
The problem has nothing to do with whether the variable lives on the stack or not. It has to do with initialization.
Variables with static storage duration, i.e. file-scope variables or local variables with the static keyword, are implicitly initialized so that (loosely speaking) all variables with arithmetic type are initialized to 0 and all pointer variables are initialized to NULL.
In contrast, variables with automatic storage duration, i.e. variables declared inside of a function, are not initialized if there is no explicit initializer and its value is indeterminate.
While you didn't show your initialization function, it apparently doesn't set all fields in mainwindow.pages and depends on the other fields being zero-initialized. When mainwindow is declared non-static, this results in your program reading some indeterminate fields which causes undefined behavior, which explains why the problem mysteriously disappears when you attempt to trim down the code.
Adding an initializer to mainwindow addresses this issue by setting any fields explicitly listed, while applying the static object initialization rules to any remaining fields not explicitly initialized.

C++ arrays and System::Single?

I'm relatively new to C++, and I'm trying to take an array within a class, and set it equal to a passed in array.
public ref class Example {
array<float> ^ myarray1 = gcnew array<float>(3);
public:
Example(float^ myarray2) {
int i = 0;
while (i<3) {
myarray[i] = myarray2[i];
i += 1;
}
}
In the main function, the constructor is called as follows:
float myarray2[] = {1,2,3};
Example ^example1 = gcnew Example(*myarray2)
The errors I get is are as follows:
System::Single' has no default indexed property (class indexer)
expression must have pointer-to-object or handle-to-C++/CLI-array
type
Both of these errors are identified as happening where I am saying myarray[i] = myarray2[i].
I would greatly appreciate any help with solving this problem. I can't see where or how System::Single is getting pulled in as an error message. And, before it is suggested, I know I can get to work with setting myarray2 as a array float like myarray1, but I want it to work passing in myarray2 as float^ myarray2.
Since you say you're new to C++, let me point out that you're not writing classic C++ there. You're writing C++/CLI, which is a set of language extensions to C++ designed to interoperate with the CLI (.NET Framework). Because of this, the type float in your code is an alias for the type System::Single of the framework.
Regarding the indexer issue, the error messages pretty much spell out the cases in which you would be allowed to use an indexer:
System::Single' has no default indexed property (class indexer)
You could use an indexer if the type had a defined indexed property. System::Single, also known as float, doesn't happen to have one.
expression must have pointer-to-object type
You could use the indexer if the type was a non-void pointer type. You'd have to declare it like this:
Example(float* myarray2) {
In this case, myarray2[i] is equivalent to the expression *(myarray2 + i).
or handle-to-C++/CLI-array type
You could use the indexer if the type was a handle (^) to a C++/CLI array type. As you already know, you'd have to declare it like this:
Example(array<float> ^ myarray2) {
The bottom line is that, although you can treat a float* (pointer to float) like a C-style array of float (as a result of the rules of C and C++ about arrays and pointer arithmetic), these things simply do not apply to the float^ (handle to float) type (which is C++/CLI-specific).
Example(float^ myarray2)
That does not mean what you think it does. You are used to C language behavior, a float[] can automatically decay to a float* to the first element of the array. Somewhat unfortunately also carried forward into C++.
But not into C++/CLI, it is fundamentally unverifiable code. And responsible for a very large number of bugs and security problems. One core problem is that your constructor has no idea how many elements are stored in the array. You hard-coded "3" but if the caller passes an array that's smaller then Very Bad Things happen.
What it actually means is "reference to a boxed copy of a System::Single". The compiler tries to make sense of that, inevitably it starts to get very confused what you try to do next. Like using the [] operator, that requires the type to have an indexer. A float doesn't have one.
You need either:
Example(array<float>^ myarray2)
Which is safe and verifiable, you can't index the array out of bounds. And you don't have to hard-code "3" anymore, you can simply use myarray2->Length instead. And you don't (usually) have the copy the array anymore, simply assign myarray1. You'd call the constructor by passing gcnew array<float> { 1, 2, 3 }.
Or:
Example(float* myarray2)
Which works just like the way it does in C and C++. And required if you want to call the constructor with that float[]. Not verifiable, you need that magic "3". Do consider adding an extra argument to pass the array length.

Why does an anonymous enum fails MISRA C 2012 rule 10.3 and a named enum doesn't?

In question:
Why do I have to cast an enum element when assigning it to a same enum variable type in C?
I was having problems with this code for failing the MISRA C 2012 rule 10.3 that states:
The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category
The code is this:
typedef enum
{
FLS_PROG_SUCCESS,
FLS_PROG_FAIL,
FLS_ERASE_SUCCESS2U,
FLS_ERASE_FAIL,
FLS_READ_SUCCESS,
FLS_READ_FAIL,
FLS_FORMAT_SUCCESS,
FLS_FORMAT_FAIL
}FLS_JobResult_t;
void Foo(void)
{
FLS_JobResult_t ProgramStatus;
/* Then I try to initialize the variable value */
ProgramStatus = FLS_PROG_SUCCESS;
...
}
And I accepted an answer that suggest that the tool may be flawed. I still do believe that but fooling around trying to fix that I put a name to the typedef enum declaration which now is:
typedef enum FLS_JobResult_tag
{
FLS_PROG_SUCCESS,
FLS_PROG_FAIL,
FLS_ERASE_SUCCESS2U,
FLS_ERASE_FAIL,
FLS_READ_SUCCESS,
FLS_READ_FAIL,
FLS_FORMAT_SUCCESS,
FLS_FORMAT_FAIL
}FLS_JobResult_t;
And as far as I know both are exactly the same. But then, surprise! The error went away! The rules checker is no longer flagging that as an error!!
Then doing some research I found this two questions:
What are the differences between these two typedef styles in C?
and
What's the difference between these two enum declarations - C?
And I realized that there are subtle differences between an anonymous enum and a named enum. But nothing that makes clear what could be the reason for the rule checker to complaint about one form of the other.
So the question is: What is the difference from an anonymous enum vs named enum that may break rule 10.3 from MISRA c 2012?
Both examples are compliant, and both for the same reasons: they are not assigning an object of a different essential type.
Let's clear up the confusion.
C grants developers/compilers a lot of freedom in its type system, but it also can lead to unintended results, with the potential for loss of value, sign or precision. MISRA-C:2012 helps enforce safer typing with its essential type model, which provides the rational basis for its rule definitions in controlling the use of type conversions and promoting awareness of implementation specific behavior (the 10.x Rules).
The essential type model replaces the MISRA-C:2004 standard’s “underlying type” model (which caused a lot of programmer grief enforcing unnecessary casts for one reason).
I suspect your tool is confused, and/or partially stuck with the older model.
The essential type rules that pertain to enumerations recognizes two different programming uses:
an object of an enum type intended to be distinct from an object with a
different enum type.
enums are a common way of holding a set of integer constants.
The C standard does not give a way of distinguishing between these uses. Therefore MISRA-C:2012 added the following distinct essential types of enumeration (while not affecting C behavior):
Named enum type - enumeration defined in this is
identified either by a tag or a typedef or used in the definition of
any object, function or type; A cast must be used if the integer
value of the enumeration constant is required.
Anonymous enum type - an enumeration which is not used in the
definition of any object, function or type. This will typically be
used to define a set of constants, which may or may not be related,
but avoids the need for casting.
An example of an anonymous enum type:
enum {D = 10, E = 20, F = 30};
Both your examples are named enum types (and they are compliant because they are the same essential type). Other examples are:
enum JOHN {A, B, C};
enum PAUL {E, F, G} PAUL;
Thus, an example of a real 10.3 violation would be:
enum PAUL bar = B;
Reference: MISRA-C:2012 Appendix D.5 "The essential type of enumerations” amplifies this very well with other examples.
With lside (type is anonymous enumeration) = rside (type is anonymous enumeration) the left and right do not know it is the same anonymous enumeration - hence potential problems.
With lside (type is named enumeration) = rside (type is _same_ named enumeration) - all is OK it is known the same enumeration is used.
The real "bug" is actually in the C standard (6.7.2.2). An enumeration constant is guaranteed by C to be of type int, but an enumeration variable may be of a number of different types, for example char.
As for which essential type that is used for enumeration constants and enumeration variables, it is described in MISRA-C:2012 appendix D.6. The enumeration constants in your code are considered to be of the same essential type as the named enum type.
So the tool is incorrect and should not issue a diagnostic.
it is (almost) always a bad idea to typedef an enum.
Much better to write it as follows:
enum FLS_JobResult_t
{
FLS_PROG_SUCCESS,
FLS_PROG_FAIL,
FLS_ERASE_SUCCESS2U,
FLS_ERASE_FAIL,
FLS_READ_SUCCESS,
FLS_READ_FAIL,
FLS_FORMAT_SUCCESS,
FLS_FORMAT_FAIL
};
void Foo(void)
{
enum FLS_JobResult_t ProgramStatus;
/* Then I try to initialize the variable value */
ProgramStatus = FLS_PROG_SUCCESS;
}

What purpose does the enum name serve?

An enum is a "named collection of constants": enum MyType_e {A, B, C};
Those constants are declared in the parent scope of the enum i.e. if the enum is declared in file scope, and is unnamed, it is equivalent to a series of e.g.#define A 0 statements
The underlying type for enum constants is always int i.e. int var = A is fully legal, although var is not of type MyType_e
So what purpose does the enum name serve?
EDIT
As per the comments below, my understanding of enums appears to be quite flawed. An enum has nothing to do with #define statements. Enums are resolved at compile time, and are typed.
Using the enum type conveys intent.
Suppose you have a function that takes an enum constant as an argument.
void foo(enum MyType_e e);
is self-documenting about what valid inputs are but:
void foo(int e);
is not. Moreover, the compiler may issue warnings if you attempt to pass incompatible values for the enum type. From Annex I ("Common warnings") of the ISO C99 specification:
An implementation may generate warnings in many situations.... The following are a few of the more common situations.
[...]
A value is given to an object of an enumeration type other than by assignment of an enumeration constant that is a member of that type, or an enumeration variable that has the same type, or the value of a function that returns the same enumeration type (6.7.2.2).
Some compilers (for example, gcc) might even generate warnings if you use switch on an enum type but neglect to handle all of its constants and don't have a default case.
While you can perfectly say
int var = A
the variant
enum mytype var = A
is better for documentatory reasons.
The answers above are good and correct, I just want to add that certain debuggers, are able to show the enum name when hovering or mointoring an enum type variable. This really helps clarity, especially when enums are used for states in state machine implementation.

Resources