【问题标题】:missing entries in array of string values字符串值数组中缺少条目
【发布时间】:2019-05-16 13:14:34
【问题描述】:

我正在尝试创建一个 const char 字符串数组,用于识别某些硬件通道。然后我想通过索引检索这些条目以在用户控制台上标记输出。其中一些通道​​未分配并用字符串“XX_UNASSIGNED_XX”标记,因此该值在数组中重复。

当我尝试在测试代码中按顺序显示这些值时,我看到 XX_UNASSIGNED_XX 只出现一次,随后被跳过。我在嵌入式硬件中打开了内存跟踪,果然,内存只列出了 XX_UNASSIGNED_XX 一次,我假设这是一种优化。

有没有办法强制编译器按原样列出内存中的每个条目、重复项和所有项?或者,是否有可能我不需要这样做,并且我尝试显示字符串的方式不正确或效率低下并且可以改进?

我已经尝试过如何显示字符串,并且因为它最终是一个指针数组,每个字符串的长度不同,我最终记录了每个字符串的长度,使用指针变量跟踪数组,然后使用snprintf 将字符串复制到一个临时字符串,然后我会显示该字符串。任何直接打印数组中值的尝试都会导致我似乎无法纠正的异常行为。

仅供参考 Display_printf 命令只是一个到 UART 终端的 printf,语法如下:

Display_printf(UART_handle,col_index, row_index, display_text))
    #define ADC_COUNT (20)

    const char* adcNamesArray[ADC_COUNT] = {
        "KP_CUR_MON",
        "A_CUR_MON",
        "A_VOLT_MON",
        "NEG_15_VOLT_MON",
        "XX_UNASSIGNED_XX",
        "FOCUS_CUR_MON",
        "XX_UNASSIGNED_XX",
        "XX_UNASSIGNED_XX",
        "K_CUR_MON",
        "XX_UNASSIGNED_XX",
        "XX_UNASSIGNED_XX",
        "XX_UNASSIGNED_XX",
        "FOCUS_VOLT_MON",
        "FARADAY_MON",
        "MFC_MON",
        "XX_UNASSIGNED_XX",
        "POS_12_VOLT_MON",
        "POS_24_VOLT_MON",
        "POS_15_VOLT_MON",
        "POS_5_VOLT_MON"
    };

    char str[20];
    char* ptr = &adcNamesArray[0];
    char* printPtr;
    int nameLength;

    for(int adc_index = 0; adc_index < ADC_COUNT; adc_index++) {
        nameLength = 0;

        while(*ptr == '\0') {
            ptr += sizeof(char);
        }
        printPtr = ptr;

        while(*ptr != '\0') {
            ptr += sizeof(char);
            nameLength++;
        }
        nameLength++;

        char* str;
        str = (char *)malloc((sizeof(char)*nameLength+1));
        snprintf(str, nameLength, "%s", printPtr);

        Display_printf(display,0,0,"ADC %d: %s", adc_index, str);
    }

所以,我希望所有 XX_UNASSIGNED_XX 条目按顺序显示,但我得到的是:

ADC 0: KP_CUR_MON  
ADC 1: A_CUR_MON  
ADC 2: A_VOLT_MON  
ADC 3: NEG_15_VOLT_MON   
ADC 4: XX_UNASSIGNED_XX   
ADC 5: FOCUS_CUR_MON   
ADC 6: K_CUR_MON   
ADC 7: FOCUS_VOLT_MON   
ADC 8: FARADAY_MON   
ADC 9: MFC_MON   
ADC 10: POS_12_VOLT_MON   
ADC 11: POS_24_VOLT_MON   
ADC 12: POS_15_VOLT_MON   
ADC 13: POS_5_VOLT_MON   
ADC 14: ▒   
ADC 15: @   
ADC 16: ▒▒▒▒   
ADC 17: @▒   
ADC 18:   
ADC 19:  

查看内存转储会给出这一点,这就解释了为什么 XX_UNASSIGNED_XX 没有多次出现。

0x0001C0D8  .  .  .  .  .  .  .  0  K  P  _  C  U  R  _  M  
0x0001C0E8  O  N  .  .  A  _  C  U  R  _  M  O  N  .  .  .  
0x0001C0F8  A  _  V  O  L  T  _  M  O  N  .  .  N  E  G  _  
0x0001C108  1  5  _  V  O  L  T  _  M  O  N  .  X  X  _  U  
0x0001C118  N  A  S  S  I  G  N  E  D  _  X  X  .  .  .  .  
0x0001C128  F  O  C  U  S  _  C  U  R  _  M  O  N  .  .  .  
0x0001C138  K  _  C  U  R  _  M  O  N  .  .  .  F  O  C  U  
0x0001C148  S  _  V  O  L  T  _  M  O  N  .  .  F  A  R  A  
0x0001C158  D  A  Y  _  M  O  N  .  M  F  C  _  M  O  N  .  
0x0001C168  P  O  S  _  1  2  _  V  O  L  T  _  M  O  N  .  
0x0001C178  P  O  S  _  2  4  _  V  O  L  T  _  M  O  N  .  
0x0001C188  P  O  S  _  1  5  _  V  O  L  T  _  M  O  N  .  
0x0001C198  P  O  S  _  5  _  V  O  L  T  _  M  O  N  .  .  
0x0001C1A8  uartMSP432E4HWAttrs  
0x0001C1A8  .  .  .  @  .  .  .  .  .  .  .  .  .  .  .  .  
0x0001C1B8  @  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .

感谢任何帮助。

【问题讨论】:

  • 因为字符串是const,编译器在数组中重复使用相同的字符串。为什么不直接使用索引访问数组? Display_printf(display,0,0,"ADC %d: %s", adc_index, adcNamesArray[adc_index]);
  • 我尝试使用索引访问它,但它返回垃圾 ADC 0:ADC 1:k▒ ADC 2:ADC 3:ADC 4:▒ ADC 5:ADC 6:ADC 7:▒ ADC 8: ADC 9:ADC 10:(空)ADC 11:(空)ADC 12:▒ ADC 13:ADC 14:ADC 15:▒ ADC 16:ADC 17:ADC 18:▒ ADC 19:知道为什么吗?
  • 什么是MSP432E4_ADC_COUNTADC_COUNT 是什么?请出示minimal reproducible example
  • @Jabberwocky 对不起,错字。我修复了它并将定义添加到代码中。
  • 您正在假设编译器如何在内存中布置字符串。你有一个指针数组,而不是字符。这些指针可以指向任何地方。您不能依赖字符串在内存中是连续的。

标签: c arrays string memory


【解决方案1】:

您假设文本在内存中是连续的,由一个或多个 NUL 字符分隔。这个假设是错误的。

这声明了一个指向你的文本的指针数组:

const char* adcNamesArray[ADC_COUNT] = {
...

只需使用该数组,您的代码就会突然变得更加简单和正确。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ADC_COUNT (20)

int main(void)
{
  const char* adcNamesArray[ADC_COUNT] = {
         "KP_CUR_MON",
         "A_CUR_MON",
         "A_VOLT_MON",
         "NEG_15_VOLT_MON",
         "XX_UNASSIGNED_XX",
         "FOCUS_CUR_MON",
         "XX_UNASSIGNED_XX",
         "XX_UNASSIGNED_XX",
         "K_CUR_MON",
         "XX_UNASSIGNED_XX",
         "XX_UNASSIGNED_XX",
         "XX_UNASSIGNED_XX",
         "FOCUS_VOLT_MON",
         "FARADAY_MON",
         "MFC_MON",
         "XX_UNASSIGNED_XX",
         "POS_12_VOLT_MON",
         "POS_24_VOLT_MON",
         "POS_15_VOLT_MON",
         "POS_5_VOLT_MON"
  };

  for (int adc_index = 0; adc_index < ADC_COUNT; adc_index++)
  {
    char *str = malloc(strlen(adcNamesArray[adc_index]) + 1);
    strcpy(str, adcNamesArray[adc_index]);
    printf("ADC %d: %s\n", adc_index, str);
  }
}

如果您的平台上由于某种原因没有strcpystrlen,您可以自己实现它们,它们是单行的。

一些解释:

  • sizeof char 定义为 1,所以你可以删除它
  • malloc 不需要 (char*) 演员表,放一个没有错,但这样做的好处是零。

【讨论】:

  • 最终,答案是我不能依赖数组的连续内存分配,或者考虑编译器可能使用的优化。我认为是这种情况,但希望有人可以解决这个问题。我最初开始按照您在这里的建议进行操作,但是由于某种原因,当我尝试以这种方式显示文本时,我使用的硬件平台会抛出一些中断标志。我想这是我必须进一步调查的事情,因为另一种方法,依靠指针来跟踪数组,是不可行的。感谢您的帮助
  • @Byers1979 你以前真的做过同样的事情吗?我想您之前的解决方案中还有另一个错误,因此您的平台抛出了一些东西。
  • 我修复了中断标志的问题,它与这个问题无关,更具体到平台。但新问题是 adcNamesArray[adc_index] 现在一次只指向一个字节。因此,例如,adcNamesArray[0] 返回“KP_CUR_MON”,然后 adcNamesArray[1] 返回“P_CUR_MON”等......不知道为什么。
  • @Byers1979 是的,adcNamesArray[0] 指向"KP_CUR_MON" 的第一个字节,adcNamesArray[1] 指向"A_CUR_MON" 的第一个字节等等。这是正常的,这就是指针的工作方式。我想你还没有完全掌握指针的概念。
  • 我知道它应该是这样工作的。我是说它不会那样做。不是 adcNamesArray[1] 指向“A_CUR_MON”的第一个字节,而是指向“KP_CUR_MON”的第二个字节,而 adcNamesArray[2] 指向“KP_CUR_MON”的第三个字节,而它应该指向“A_VOLT_MON” .我不确定它为什么这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-09
  • 2015-03-15
  • 1970-01-01
  • 1970-01-01
  • 2020-12-18
相关资源
最近更新 更多