顯示具有 GCC 標籤的文章。 顯示所有文章
顯示具有 GCC 標籤的文章。 顯示所有文章

2009年11月28日 星期六

GCC 最佳化參數對 const 變數的影響

之前有寫過幾篇關於 const 變數的文章
這次要實驗的程式碼為
/* main.c */
#include <stdio.h>

void foo(const int* const);
void bar(int);

int main(int argc, char* argv[])
{
    const int value = 11;
    printf("%d\n", value);
    foo(&value);
    bar(value);
    printf("%d\n", value);
    return 0;
}

void foo(const int* const value)
{
    int* tmp = (int*) value;
    *tmp = 22;
    printf("%d\n", *value);
}

void bar(int value)
{
    printf("%d\n", value);
}
以及
/* main.cpp */
#include <cstdio>

void foo(const int* const);
void bar(int);

using namespace std;

int main(int argc, char* argv[])
{
    const int value = 11;
    printf("%d\n", value);
    foo(&value);
    bar(value);
    printf("%d\n", value);
    return 0;
}

void foo(const int* const value)
{
    int* tmp = const_cast<int*>(value);
    *tmp = 22;
    printf("%d\n", *value);
}

void bar(int value)
{
    printf("%d\n", value);
}
為了要實驗各個參數寫了一個 Makefile
all:
    $(CC) -Wall -g -O0 main.c -o main-O0
    @echo main-O0 && ./main-O0
    $(CC) -Wall -g -O1 main.c -o main-O1
    @echo main-O1 && ./main-O1
    $(CC) -Wall -g -Os main.c -o main-Os
    @echo main-Os && ./main-Os
    $(CC) -Wall -g -O2 main.c -o main-O2
    @echo main-O2 && ./main-O2
    $(CC) -Wall -g -O3 main.c -o main-O3
    @echo main-O3 && ./main-O3
    $(CXX) -Wall -g -O0 main.cpp -o main-O0
    @echo main-O0 && ./main-O0
    $(CXX) -Wall -g -O1 main.cpp -o main-O1
    @echo main-O1 && ./main-O1
    $(CXX) -Wall -g -Os main.cpp -o main-Os
    @echo main-Os && ./main-Os
    $(CXX) -Wall -g -O2 main.cpp -o main-O2
    @echo main-O2 && ./main-O2
    $(CXX) -Wall -g -O3 main.cpp -o main-O3
    @echo main-O3 && ./main-O3
執行 make 後得到的結果為
cc -Wall -g -O0 main.c -o main-O0
main-O0
11
22
22
22
cc -Wall -g -O1 main.c -o main-O1
main-O1
11
22
11
11
cc -Wall -g -Os main.c -o main-Os
main-Os
11
22
11
11
cc -Wall -g -O2 main.c -o main-O2
main-O2
11
22
11
11
cc -Wall -g -O3 main.c -o main-O3
main-O3
11
22
11
11
g++ -Wall -g -O0 main.cpp -o main-O0
main-O0
11
22
11
11
g++ -Wall -g -O1 main.cpp -o main-O1
main-O1
11
22
11
11
g++ -Wall -g -Os main.cpp -o main-Os
main-Os
11
22
11
11
g++ -Wall -g -O2 main.cpp -o main-O2
main-O2
11
22
11
11
g++ -Wall -g -O3 main.cpp -o main-O3
main-O3
11
22
11
11
由結果可以看出 C++ 對於 const 變數的處理都一樣
反而在 C 上面對預設的 -O0 參數不會執行任何常數字面的最佳化處理

2009年11月16日 星期一

GCC C++ Compiler 根本沒有還原 const 變數的數值,只不過先行代換掉使用 const 變數的地方。

延續前三篇文章的討論
C++ Programming: Call by Reference/Value/Pointer and const_cast
GCC C++ Compiler 會聰明地幫你還原 const 變數的數值
GCC C++ Compiler 對於 const 變數的處理到底會有多聰明呢?
這次實驗的程式碼如下
#include <iostream>

void foo(const int&);
void bar(const int&);

using namespace std;

int main(int argc, char* argv[])
{
    const int value = 11;
    cout << value << endl;
    foo(value);
    cout << value << endl;
    bar(value);
    cout << value << endl;
    cout << *(int*)&value << endl;
    return 0;
}

void foo(const int& value)
{
    int& tmp = const_cast<int&>(value);
    tmp = 22;
}

void bar(const int& value)
{
    cout << value << endl;
}
正如網友 jclin 提到的「我比較不相信 GCC 會幫你還原 const value 的作法. 只是 compiler 知道那是 const, 基於 optimization 的角度
還有 chihchun 提到的「main::value 是一個 alias, compiler (g++ 4.3.4) 會替換成 integral literal,但是依然會在 Stack 中配置此變數供人使用。
GCC C++ Compiler 只不過是把原始碼先轉換成以下這段
#include <iostream>

void foo(const int&);
void bar(const int&);

using namespace std;

int main(int argc, char* argv[])
{
    const int value = 11;
    cout << 11 << endl;
    foo(value);
    cout << 11 << endl;
    bar(value);
    cout << 11 << endl;
    cout << *(int*)&value << endl;
    return 0;
}

void foo(const int& value)
{
    int& tmp = const_cast<int&>(value);
    tmp = 22;
}

void bar(const int& value)
{
    cout << value << endl;
}
const 變數並不代表它無法被改變數值,透過 const_cast 還是可以改變數值的,只不過已經先被當作字面常數替換掉的地方,在 C++ 程式碼的運作上不是那麼容易瞭解。

2009年11月15日 星期日

GCC C++ Compiler 對於 const 變數的處理到底會有多聰明呢?

延續前兩篇文章的程式碼實驗
C++ Programming: Call by Reference/Value/Pointer and const_cast
GCC C++ Compiler 會聰明地幫你還原 const 變數的數值
這次想要實驗的程式碼片段如下
#include <iostream>

struct Foo {
    const int value;
};

void foo(const struct Foo* const);
void foofoo(const struct Foo* const);

using namespace std;

int main(int argc, char* argv[])
{
    const struct Foo bar = {11};
    cout << bar.value << '\t' << &bar.value << endl;
    foo(&bar);
    cout << bar.value << '\t' << &bar.value << endl;
    foofoo(&bar);
    cout << bar.value << '\t' << &bar.value << endl;
}

void foo(const struct Foo* const bar)
{
    static struct Foo inner = {22};
    struct Foo** tmp = const_cast<struct Foo**>(&bar);
    cout << *tmp << '\t' << bar << '\t' << bar->value << endl;
    *tmp = &inner;
    cout << *tmp << '\t' << bar << '\t' << bar->value << endl;
}

void foofoo(const struct Foo* const bar)
{
    int &value = const_cast<int&>(bar->value);
    value = 22;
}
編譯後執行的結果為
11    0xbfbb3090
0xbfbb3090    0xbfbb3090    11
0x804a034    0x804a034    22
11    0xbfbb3090
22    0xbfbb3090
對照程式碼就可以發現呼叫 foo() 後 const 變數 bar 被還原成原本的數值了
不過呼叫 foofoo() 後 const 變數 bar 底下的 const 變數 value 並沒有被還原成原本的數值
所以 GCC C++ Compiler 對 const 變數數值的還原保護僅限於直接傳入函式的變數本身
並不包含該 const 變數底下的 const 變數,到這時總算是解決了 $4 心中的疑惑
為什麼兩三年前寫 C++ 時,使用 const_cast 可以改變 const 變數的數值
而在 H4 聚會的實驗時反而遇到了跟 $4 過去經驗乍看下相衝突的結果 :-)