2016-08-21 85 views
0

編輯: 我已經做了一些假設,例如靜態變量將在運行時第一次被調用時創建並初始化一次。爲什麼示例A編譯和示例B錯誤「初始化器元素不是常量」

我現在知道情況並非如此,現在只是定義一個靜態並返回它的指針,並且有一個init函數在程序的開始時調用一次,所以基本上和我在做時一樣正在使用全局變量,但將其保持在全球範圍之外。

原文:

我試圖避免全局變量作爲一般建議,但需要,我可以參考多種功能,而無需一個對象不斷傳遞給每一個功能的一些靜態數據(不過,如果這最終ulmatmatly不起作用,我可能不得不訴諸於此)

另一個潛在的優勢是,因爲我使用這個功能的大部分功能將被頻繁調用,只有初始化一次數據,永遠不應該改變應該儘量減少性能損失

我想到的方法是創建一個靜態變量並初始化一次,如果我需要在單個函數中使用它,我會直接在函數中初始化,然後使用它,如果我需要它多種功能我會初始化它在一個單獨的靜態函數,其他人可致電指針

編輯: WINDOWS是宏觀定製

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

而且編譯器MinGW的64位

例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的代碼的無效

+6

兩者都沒有問題。靜態變量必須用常量表達式進行初始化,並且函數調用不是其中之一。 –

+1

看起來像Java:不可讀,恕我直言。 – wildplasser

+0

看來你正在用一個非常特定的編譯器測試你的代碼,這個編譯器定義了宏'WINDOWS'。然後你總結一些關於你的代碼的一致性。如果這實際上是一個Microsoft編譯器,請注意它甚至不遵守C99標準。 –

回答

1

您不能使用函數的返回值來初始化一個具有static存儲的變量:

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

的2個代碼片段處理您已不提供的定義不同的結構,既不應該編譯,但要注意,如果沒有定義WINDOWSgetPath操縱未初始化的結構result,所以任何事情都有可能發生,包括編譯器在玩你的技巧。

由於這兩個函數定義爲static inline,編譯器只會報告錯誤,當它實際嘗試在呼叫站點內聯地擴展getPath,並且仍然在定義的位置報告錯誤內聯函數。

此外,這裏有一些問題getPath

  • 它調用上潛在的重疊對象memcpy,這也將調用未定義的行爲:使用memmove代替。

  • result.executableStringLen = ++j;不正確,應刪除。如果發現'/',長度已經被更新,但搜索之前,你應該初始化它result.executableStringLen = i;

  • 如果沒有找到'/',您可以有效地清除陣列除了第一個字節。你應該從j = result.executableStringLen開始。

+0

我玩過非靜態和非內聯函數的結果都是一樣的。 我不認爲結構的定義很重要,因爲它們都很簡單 感謝getPath我將繼續並更新我的代碼,我也不知道memmove命令存在。 –