数组部分为空

Array partially empty

我已经为我的 C++ 应用程序 运行 在 STM32F407VG 上编写了启动和喜欢脚本。

问题是我有一个结构数组,尽管进行了初始化,但结构字段 str 始终为零。结构中的其他字段已正确初始化。我不明白我做错了什么,我猜启动脚本中的某些初始化部分丢失了。

数组声明如下:

struct elem{
    uint32_t str;
    uint32_t value;
    uint32_t value2;
};

const struct elem array[]{
    {(uint32_t)(*(uint32_t*)"CM1"), 1, 1},
    {(uint32_t)(*(uint32_t*)"CM2"), 2, 2},
    {(uint32_t)(*(uint32_t*)"CM3"), 3, 3}
};

启动脚本的相关部分:

inline void static_init()
{
  for (void (**p)() = __preinit_array_start; p < __preinit_array_end; ++p)
    (*p)();

  for (void (**p)() = __init_array_start; p < __init_array_end; ++p)
    (*p)();
}

void reset_handler(void)
{

  unsigned long *source;
  unsigned long *destination;

  // Copying data from Flash to RAM
  source = &_data_flash;
  for (destination = &_data_begin; destination < &_data_end;)
  {
      *(destination++) = *(source++);
  }

  // default zero to undefined variables
  for (destination = &_bss_begin; destination < &_bss_end;)
  {
      *(destination++) = 0;
  }

  static_init();

#ifndef __NO_SYSTEM_INIT
  SystemInit();
#endif

  // starting main program
  main();
}

和链接描述文件:

/* Entry Point */
ENTRY(reset_handler)

_estack = 0x20010000; /* end of 128K RAM */
/* Specify the memory areas */
/*
0x08000000 until 0x08010000 is reserved for BOOTLOADER! (64k)
*/
MEMORY
{
  EEPROM (rwx)    : ORIGIN = 0x08010000, LENGTH = 64K /*fake EEPROM!*/
  FLASH (rx)      : ORIGIN = 0x08020000, LENGTH = 896K
  RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 128K
  RAM2 (rw)      : ORIGIN = 0x10000000, LENGTH = 64K
}

SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    __intvec_start__ = .;
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    _text = .;
      *(.text)           /* .text sections (code) */
    _text2 = .;
      *(.text*)          /* .text* sections (code) */
    _rodata = .;
      *(.rodata)         /* .rodata sections (constants, strings, etc.) */
      *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
      *(.glue_7)         /* glue arm to thumb code */
      *(.glue_7t)        /* glue thumb to arm code */
      *(.eh_frame)
    _init_data = .;
    KEEP (*(.init))
    KEEP (*(.fini))
    . = ALIGN(4);
      _etext = .;        /* define a global symbols at end of code */
  } > FLASH

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* used by the startup to initialize data */
  _data_flash = _sidata;

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data :
  {
    . = ALIGN(4);
    _data_begin = .;
    *(.data)
    *(.data*)

    . = ALIGN(4);
    _data_end = .;
  } >RAM AT> FLASH


  .bss (NOLOAD) :
  {
      . = ALIGN(4);
      _bss_begin = .;
      __bss_start__ = _bss_begin;
      *(.bss)
      *(.bss*)
      *(COMMON)
      . = ALIGN(4);
      _bss_end = .;
      __bss_end__ = _bss_end;
  } > RAM

  stack_size = 1024;
  __stack_end__ = ORIGIN(RAM)+LENGTH(RAM);
  __stack_start__ = __stack_end__ - stack_size;

  heap_size = 0;
  __heap_end__ = __stack_start__;
  __heap_start__ = __heap_end__ - heap_size;

  . = __stack_start__;
  ._stack :
  {
      PROVIDE ( end = . );
      . = . + stack_size;
      . = . + heap_size;
      . = ALIGN(4);
  } > RAM

  _siccmram = LOADADDR(.ram2);
  .ram2 (NOLOAD) :
  {
    . = ALIGN(4);
    *(.ram2);
          *(.ram2*);
    . = ALIGN(4);
  } > RAM2 AT> FLASH

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
      libc.a ( * )
      libm.a ( * )
      libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}

这应该可以工作并且没有 UB。
但是,它依赖于字节序。

#include <iostream>
#include <cstdint>
#include <cstring>

using namespace std;

struct elem {
    uint32_t str;
    uint32_t value;
    uint32_t value2;
};

uint32_t makeint(const char str[4])
{
    uint32_t val;
    memcpy( &val, str, 4 );
    return val;
}

const elem arr[] = {
    {makeint("CM1"), 1, 1},
    {makeint("CM2"), 2, 2},
    {makeint("CM3"), 3, 3}
};

int main()
{
    for (auto& e : arr)
        cout << e.str << endl;

    cout << "\ndone\n";
}

看到了here

您可以使用多字符文字:参见 character_literal 的 (6.)。

注意单引号:

const struct elem array[]{
    {'CM1', 1, 1},
    {'CM2', 2, 2},
    {'CM3', 3, 3}
};

您可以看到 gcc 如何计算多字符文字:

https://gcc.gnu.org/onlinedocs/cpp/Implementation-defined-behavior.html#Implementation-defined-behavior

The compiler evaluates a multi-character character constant a character at a time, shifting the previous value left by the number of bits per target character, and then or-ing in the bit-pattern of the new character truncated to the width of a target character. The final bit-pattern is given type int, and is therefore signed, regardless of whether single characters are signed or not. If there are more characters in the constant than would fit in the target int the compiler issues a warning, and the excess leading characters are ignored.