3

我一直在尝试更改一些语法,以强制用户在访问我编写的 STM32F4 Cortex-M4 CPU 的简单库之前启用外围时钟。

在以下代码挣扎了几个小时后,我找不到我做错了什么,并尝试用 linux g++ 编译它,它成功了。

这是关于 ARM g++ 的编译器错误,还是我一直在使用 linux g++ 之前允许我使用的一些非标准行为?

这是一个简化的代码示例:

#include <cstdint>

template<std::size_t port>
class Port
{
public: //Declarations
  enum class PinMode
  {
    Input = 0x0,
    Output = 0x1,
    Alternate = 0x2,
    Analog = 0x3
  };

  template<uint8_t nPin, PinMode mode>
  class Pin
  {

  };

  template<uint8_t nPin>
  class Pin<nPin, PinMode::Output>
  {
  public: //Declarations
    enum class OutputSpeed : uint32_t
    {
      Low,
      Medium,
      Fast,
      High
    };

    enum class PullMode : uint32_t
    {
      None = 0x0,
      PullUp = 0x1,
      PullDown = 0x2
    };

  public: //Methods
    void setOutputSpeed(OutputSpeed const ospeed) volatile;
    void setPullMode(PullMode const ppm) volatile;

    void set() volatile
    {
      reinterpret_cast<Port<port> volatile*>(port)->m_BSRR |= static_cast<uint16_t>(0x1) <<nPin;
    }
    void reset() volatile;

    bool getOutputState() volatile;
  }; //END OutputPin

public: //Registers
  uint32_t m_BSRR;
}; //END Port

int main()
{
  auto pin = Port<0>::Pin<5, Port<0>::PinMode::Output>();
  pin.set();
}

ARM g++ 输出。

Using built-in specs.
COLLECT_GCC=arm-none-eabi-g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-none-eabi/4.8.2/lto-wrapper
Target: arm-none-eabi
Configured with: ../configure --target=arm-none-eabi --prefix=/usr --libexecdir=/usr/lib --with-pkgversion='Arch Repository' --with-bugurl=https://bugs.archlinux.org/ --enable-multilib --enable-interwork --enable-languages=c,c++ --with-newlib --with-gnu-as --with-gnu-ld --disable-nls --disable-shared --disable-threads --with-headers=newlib/libc/include --disable-libssp --disable-libstdcxx-pch --disable-libmudflap --disable-libgomp --with-system-zlib --disable-newlib-supplied-syscalls
Thread model: single
gcc version 4.8.2 (Arch Repository) 
COLLECT_GCC_OPTIONS='-std=c++11' '-v'
 /usr/lib/gcc/arm-none-eabi/4.8.2/cc1plus -quiet -v -D__USES_INITFINI__ test.cpp -quiet -dumpbase test.cpp -auxbase test -std=c++11 -version -o /tmp/cc6TlpeV.s
GNU C++ (Arch Repository) version 4.8.2 (arm-none-eabi)
    compiled by GNU C version 4.8.2 20140206 (prerelease), GMP version 5.1.3, MPFR version 3.1.2-p5, MPC version 1.0.2
warning: GMP header version 5.1.3 differs from library version 6.0.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/lib/gcc/arm-none-eabi/4.8.2/../../../../arm-none-eabi/sys-include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/arm-none-eabi/4.8.2/../../../../arm-none-eabi/include/c++/4.8.2
 /usr/lib/gcc/arm-none-eabi/4.8.2/../../../../arm-none-eabi/include/c++/4.8.2/arm-none-eabi
 /usr/lib/gcc/arm-none-eabi/4.8.2/../../../../arm-none-eabi/include/c++/4.8.2/backward
 /usr/lib/gcc/arm-none-eabi/4.8.2/include
 /usr/lib/gcc/arm-none-eabi/4.8.2/include-fixed
 /usr/lib/gcc/arm-none-eabi/4.8.2/../../../../arm-none-eabi/include
End of search list.
GNU C++ (Arch Repository) version 4.8.2 (arm-none-eabi)
    compiled by GNU C version 4.8.2 20140206 (prerelease), GMP version 5.1.3, MPFR version 3.1.2-p5, MPC version 1.0.2
warning: GMP header version 5.1.3 differs from library version 6.0.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 8ead046d6b54a8fe43e9a23d5562e5d4
test.cpp: In function 'int main()':
test.cpp:60:7: error: 'class Port<0u>::Pin<5u, (Port<0u>::PinMode)1>' has no member named 'set'
   pin.set();
       ^

G++ 输出:

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: /build/gcc/src/gcc-4.8-20140206/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-cloog-backend=isl --disable-cloog-version-check --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --disable-multilib --disable-werror --enable-checking=release
Thread model: posix
gcc version 4.8.2 20140206 (prerelease) (GCC) 
COLLECT_GCC_OPTIONS='-std=c++11' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/cc1plus -quiet -v -D_GNU_SOURCE test.cpp -quiet -dumpbase test.cpp -mtune=generic -march=x86-64 -auxbase test -std=c++11 -version -o /tmp/ccgCeLLA.s
GNU C++ (GCC) version 4.8.2 20140206 (prerelease) (x86_64-unknown-linux-gnu)
    compiled by GNU C version 4.8.2 20140206 (prerelease), GMP version 5.1.3, MPFR version 3.1.2-p5, MPC version 1.0.2
warning: GMP header version 5.1.3 differs from library version 6.0.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../x86_64-unknown-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2
 /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/x86_64-unknown-linux-gnu
 /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/backward
 /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/include
 /usr/local/include
 /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/include-fixed
 /usr/include
End of search list.
GNU C++ (GCC) version 4.8.2 20140206 (prerelease) (x86_64-unknown-linux-gnu)
    compiled by GNU C version 4.8.2 20140206 (prerelease), GMP version 5.1.3, MPFR version 3.1.2-p5, MPC version 1.0.2
warning: GMP header version 5.1.3 differs from library version 6.0.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 51ac5eb9b6c30af2da1950e6dfed6398
COLLECT_GCC_OPTIONS='-std=c++11' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 as -v --64 -o /tmp/ccWIQqrr.o /tmp/ccgCeLLA.s
GNU assembler version 2.24 (x86_64-unknown-linux-gnu) using BFD version (GNU Binutils) 2.24
COMPILER_PATH=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/:/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/:/usr/lib/gcc/x86_64-unknown-linux-gnu/:/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/:/usr/lib/gcc/x86_64-unknown-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/:/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-std=c++11' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/collect2 --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/crt1.o /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/crti.o /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/crtbegin.o -L/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2 -L/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../.. /tmp/ccWIQqrr.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/crtend.o /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/crtn.o
4

2 回答 2

2

您的代码中有两个问题。

不知道为什么,但是在模板中有枚举类不能正常工作。由于它是模板和新 c++ 功能的极端案例,因此很难在标准中找到禁止它的确切位置。它甚至可能是一个编译器错误。

因此,固定代码如下所示:

#include <cstdint>

  enum class PinMode
  {
    Input = 0x0,
    Output = 0x1,
    Alternate = 0x2,
    Analog = 0x3
  };
    enum class OutputSpeed : uint32_t
    {
      Low,
      Medium,
      Fast,
      High
    };

    enum class PullMode : uint32_t
    {
      None = 0x0,
      PullUp = 0x1,
      PullDown = 0x2
    };

template<std::size_t port>
class Port
{
public: //Declarations


  template<uint8_t nPin, PinMode mode>
  class Pin;

  template<uint8_t nPin>
  class Pin<nPin, PinMode::Output>
  {

  public: //Methods
    void setOutputSpeed(OutputSpeed const ospeed) volatile;
    void setPullMode(PullMode const ppm) volatile;

    void set() volatile
    {
      reinterpret_cast<Port<port> volatile*>(port)->m_BSRR |= static_cast<uint16_t>(0x1) <<nPin;
    }
    void reset() volatile;

    bool getOutputState() volatile;
  }; //END OutputPin

public: //Registers
  uint32_t m_BSRR;
}; //END Port

int main()
{
    auto pin = Port<0>::Pin< 5, PinMode::Output >();
  pin.set();
}
于 2014-04-17T08:31:20.350 回答
1

不是真正的“答案”,而是太多文字无法写入评论。我在我的 g++ 4.8.2 for x86-64 中看到了同样的问题(从源代码自制,大约在 3 月底或 4 月初)。

似乎编译器正在选择您的通用模板,而不是专用模板。

  template<uint8_t nPin, PinMode mode>
  class Pin
  {

  };

确实没有set会员。如果我set在该类中添加一个成员,代码就会编译。我不确定为什么编译器认为使用它比使用专用类更好。我怀疑这是 4.8.2 中的错误。

(我确实注意到您的 x86-64 的 g++ 4.8.2 是“预发布版”,这可以解释为什么它在两种架构上有所不同)。

它在 clang++ 3.5(截至昨天的不稳定分支)和 g++ 4.6.3 中编译。它不能用 clang++ 2.9 编译。

于 2014-04-17T08:19:50.183 回答