为什么示例A编译和示例B错误“初始化元素不是常量”

时间:2016-08-21 22:02:06

标签: c compiler-errors c11

编辑: 我做了一些假设,例如静态变量将在运行时第一次调用函数时创建并初始化。

我现在知道情况并非如此,现在只需定义一个静态并返回它的指针,并在程序开始时调用一次init函数,因此基本上与我在执行时的操作相同使用全局变量但保持全局范围。

原件:

我正在尝试避免通常建议的全局变量,但需要一些我可以在多个函数中引用的静态数据,而不必经常将对象传递给每个函数(尽管如果这最终不起作用我可能不得不诉诸于那个)

另一个潜在的优势是因为我使用它的大部分功能都经常被调用,只对初始化一次的数据应该永远不会改变应该最小化性能损失。

我提出的方法是创建一个静态变量并启动它一次,如果我需要在单个函数中使用它我会直接在函数内初始化然后使用它,如果我需要多个函数我将在一个单独的静态函数中启动它,其他人可以调用指针

编辑: WINDOWS是一个自定义宏

#ifndef WINDOWS
  #if defined(_WIN32) || defined(_WIN64)
    #define WINDOWS
  #endif
#endif

编译器也是MinGW 64bit

示例A编译很好但是示例B引发错误“初始化元素不是常量”

示例A:

static ProgramPath getPath() {
  ProgramPath result;
    // Get Executable Path    
#ifdef WINDOWS
  GetModuleFileName(NULL, result.executablePath, sizeof(result.executablePath));
#endif

  // Seperate Path and Executable into Seperate Variables
  for (unsigned int i = 0; i < sizeof result.executablePath; ++i) {
    // Convert \ to /
    if (result.executablePath[i] == 0x5c) {
      result.executablePath[i] = 0x2F;
    } else if (result.executablePath[i] == 0x0) { // 0x0 means we've reached end of string.
      unsigned int j;

      // Get Executable Name Sub String
      for (j = i - 1; j > 0; --j) {
        if (result.executablePath[j] == 0x2F) { // Stop when we reach a /
          result.executableStringLen = i - j;
          memcpy(&result.executable, &result.executablePath[j + 1], result.executableStringLen); // Copy Executable SubString into correct variable
          break;
        }
      }

      result.executableStringLen = ++j;

      // Remove Executable from Path
      for (; j < i; ++j) {
        result.executablePath[j] = 0x0;
      }
      break;
    }
  }

  CA_VERBOSE_DEBUG("Executable: %s", executable);
  CA_PRINT_DEBUG("Executable Path: %s", executablePath);

  return result;
}

static inline ProgramPath *getPathInfo() {
  static ProgramPath programPath = getPath();
  return &programPath;
}

例B:

static GraphicsInfo getGraphicsInfo() {
  GraphicsInfo result;

  result.internalPixelFormat = GL_BGRA;
  result.internalPixelType = GL_UNSIGNED_INT_8_8_8_8_REV;

  // Get Preferred Internal Pixel Format
  if (glGetInternalformativ) {
    const GLenum preferedInternalFormats[4] = {
      GL_RGB,
      GL_BGR,
      GL_RGBA,
      GL_BGRA
    };

    GLint test;
    // Check for Internally Supported Formats and Use Best One
    for (int i = 3; i >= 0; --i) {
      // Check for Prefered
      glGetInternalformativ(GL_RENDERBUFFER, preferedInternalFormats[i], GL_INTERNALFORMAT_PREFERRED, 1, &test);

      if (test == GL_TRUE) {
        result.internalPixelFormat = preferedInternalFormats[i];
        break;
      }
    }
  }

  return result;
}

static inline GraphicsInfo *CA_getGraphicsInfo() {
  static GraphicsInfo result = getGraphicsInfo(); // Error Occurs Here
  return &result;
}

我也试过评论示例B中的大部分代码都无济于事

1 个答案:

答案 0 :(得分:1)

您无法从函数的返回值初始化具有static存储的变量:

static inline GraphicsInfo *CA_getGraphicsInfo() {
    static GraphicsInfo result = getGraphicsInfo(); // Error Occurs Here
    return &result;
}

2个代码片段处理您未提供定义的不同结构,也不应编译,但请注意,如果未定义WINDOWSgetPath将操作未初始化的结构{{1}所以任何事情都可能发生,包括编译器在你身上耍花招。

由于两个函数都定义为result,因此编译器也可能仅在实际尝试在呼叫站点内联展开static inline时报告错误,并且仍然报告错误内联函数定义的位置。

此外,以下是getPath

的一些问题
  • 它会在可能重叠的对象上调用getPath,这也会调用未定义的行为:改为使用memcpy

  • memmove不正确,应予以删除。如果找到result.executableStringLen = ++j;,则已更新长度,但您应在搜索到'/'之前对其进行初始化

  • 如果找不到result.executableStringLen = i;,则除了第一个字节外,有效清除数组。您应该从'/'

  • 开始