简体   繁体   中英

Copy constructor for C volatile bitfield struct

Good day

I am trying to use a C SD driver/file system libary (Keil MDK), in a C++11 project. It was added by the Pack manager in Keil MDK 5.23. I am compiling with ARMCC 5.06u4

I get the warning class "_ARM_MCI_STATUS" has no suitable copy constructor" which is odd, because the header it is declared in has extern "C" { .

By default, the pack has no option to set it to C or C++, but I have manually added the file as a C file. Still a problem.

The struct is declared, within extern "C" { as:

typedef volatile struct _ARM_MCI_STATUS {
    uint32_t command_active   : 1;        ///< Command active flag
    uint32_t command_timeout  : 1;        ///< Command timeout flag (cleared on start of next command)
    uint32_t command_error    : 1;        ///< Command error flag (cleared on start of next command)
    uint32_t transfer_active  : 1;        ///< Transfer active flag
    uint32_t transfer_timeout : 1;        ///< Transfer timeout flag (cleared on start of next command)
    uint32_t transfer_error   : 1;        ///< Transfer error flag (cleared on start of next command)
    uint32_t sdio_interrupt   : 1;        ///< SD I/O Interrupt flag (cleared on start of monitoring)
    uint32_t ccs              : 1;        ///< CCS flag (cleared on start of next command)
    uint32_t reserved         : 24;
} ARM_MCI_STATUS;

The problem occurs when the struct is being returned at:

static ARM_MCI_STATUS GetStatus (MCI_RESOURCES *mci) {
  return mci->info->status;
}

Where status is declared as ARM_MCI_STATUS status; . I don't see why it should be an issue.

If I compile without the --cpp then it compiles without issue.

Any suggestions?

In C++ the default copy constructor is for a const reference. You however, are passing in a const volatile reference; and no copy constructor is made by default for that.

You may find it better to flag each member of your struct as volatile rather than the entire struct.

Just because your struct is marked extern "C" doesn't mean it won't still be compiled as C++ code.

This means that return mci->info->status; invokes the implicitly generated copy constructor. Because _ARM_MCI_STATUS is marked volatile , it's members are, which means the default copy constructor which takes T& can't bind to the volatile lvalue reference it's passed.

This is explained in the cppreference explanation :

Otherwise, the implicitly-declared copy constructor is T::T(T&). ( Note that due to these rules, the implicitly-declared copy constructor cannot bind to a volatile lvalue argument. )

And also in the actual standard (Just having a hard time finding the correct clause but it's in there).

To resolve this issue in Keil µVision 5.23, I removed the global "--cpp" flags. I then made sure that all the C++ file are in their own source groups in the project. In the options for that group, under the "C/C++" tab, in the "Misc Controls" field added the "--cpp" flag.

The options are obtained by right clicking on the folder in the project view.

Cpp来源组的“选项”选项卡

At the moment it compiles without error. The issue seems to be that µVision 5.23 will compile all the files, c or cpp, as C++ if the --cpp flag is set globally. Unlike Eclipse there does not seem to be a way to set different flags for cpp and c files.

Thanks to UKMonkey and Rick Astley. Learned something about volatile and C++.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM