- PR -

C++のコンパイルでOSによって結果が異なる

投稿者投稿内容
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2004-09-07 15:42
コード:
#include <iostream.h>

#include <time.h>
#include <sys/time.h>
using namespace std;

class Age
{
unsigned int yy, mm, dd;
unsigned int age;
public:
Age(unsigned int *, unsigned int *, unsigned int *);
unsigned int Do(void);
~Age(void);
};

Age::Age(unsigned int *y, unsigned int *m, unsigned int *d)
{
yy = *y;
mm = *m;
dd = *d;
}

Age::~Age(void)
{
// delete this;
}

unsigned int Age::Do(void)
{
struct timeval *ts;
struct tm *tm;

gettimeofday(ts, NULL);
tm = localtime((const time_t *)&ts->tv_sec);

tm->tm_year += 1900;

if(yy > tm->tm_year) return(0);
else {
yy = tm->tm_year - yy;
if(yy != 0){
if(tm->tm_mon+1 == mm){
if(tm->tm_mday == dd);
else if(tm->tm_mday < dd) yy -= 1;
}
else if(tm->tm_mon+1 < mm) yy -= 1;
}
}

age = yy;

return age;
}

int main(void)
{
unsigned int y, m, d;
unsigned int old;

cout << "誕生年(西暦)は? ";
cin >> y;

cout << "誕生月は?(1-12) ";
cin >> m;

cout << "誕生日は?(1-31) ";
cin >> d;

Age age((unsigned int *)&y, (unsigned int *)&m, (unsigned int *)&d);
old = age.Do();

cout << old << "歳" << endl;

return(0);
}



上のソースを Solaris8 の g++ 3.2 でコンパイル後、実行すれば何の問題も無く動きます。
しかし、
上のソースを、 RedHat9 の g++ 3.2.2 でコンパイル後、実行すれば・・・

$ ./a.out
誕生年(西暦)は? 2004
誕生月は?(1-12) 9
誕生日は?(1-31) 7
0歳
セグメンテーション違反です

常にセグメンテーション・フォルトしてしまいます。苦肉の策で、

コード:
//#include <iostream.h>

#include <stdio.h>
#include <time.h>
#include <sys/time.h>
using namespace std;

class Age
{
unsigned int yy, mm, dd;
unsigned int age;
public:
Age(unsigned int *, unsigned int *, unsigned int *);
unsigned int Do(void);
~Age();
};

Age::Age(unsigned int *y, unsigned int *m, unsigned int *d)
{
yy = *y;
mm = *m;
dd = *d;
}

Age::~Age(void)
{
}

unsigned int Age::Do(void)
{
struct timeval *ts;
struct tm *tm;

gettimeofday(ts, NULL);
tm = localtime((const time_t *)&ts->tv_sec);

tm->tm_year += 1900;

if(yy > tm->tm_year) return(0);
else {
yy = tm->tm_year - yy;
if(yy != 0){
if(tm->tm_mon+1 == mm){
if(tm->tm_mday == dd);
else if(tm->tm_mday < dd) yy -= 1;
}
else if(tm->tm_mon + 1 < mm) yy -= 1;
}
}

age = yy;

return age;
}

int main(void)
{
unsigned int y, m, d;
unsigned int old;

// cout << "誕生年(西暦)は? ";
printf("誕生年(西暦)は? ");
scanf("%d", &y);
// cin >> y;

// cout << "誕生月は?(1-12) ";
printf("誕生月は?(1-12) ");
scanf("%d", &m);
// cin >> m;

// cout << "誕生日は?(1-31) ";
printf("誕生日は?(1-31) ");
scanf("%d", &d);
// cin >> d;

Age age((unsigned int *)&y, (unsigned int *)&m, (unsigned int *)&d);
old = age.Do();

// cout << old << "歳" << endl;
printf("%d歳\n", old);

return(0);
}



ソースをこんな風に、「スタンダード・テンプレート」?を使わないように printf と
scanf で代用するようにしたら問題は解消されました。

今後も、 C++ でプログラミングする場合、この様な移植作業も念頭に置いて作業しなければ
ならないのでしょうか?

全く訳が判りません。

[ メッセージ編集済み 編集者: コブラ 編集日時 2004-09-07 15:42 ]
NAO
ぬし
会議室デビュー日: 2001/10/24
投稿数: 1256
お住まい・勤務地: 神奈川のはずれから東京の下町
投稿日時: 2004-09-07 17:12
今日は。

ちょっと状況が違いますが、こういった事もあります。

Solaris上でユーザーが作ったAPがありました。
でもって、ある時にSolarisのパッチを当てたら突然APが起動しなくなりました。

結論としてはユーザー作成APのバグだったのですが、
何故に顕在化しなかったかと言えば、システムコールのチェックが当該パッチの際に
チェックが厳密になる様に仕様が変更された事が原因でした。

と言う事をふまえた上で。

gccのバージョンが異なっているようですのでそう言った可能性も無きにしもあらずです。
gccバージョンが違う時点で既にそのまま動くと思わずにステップ実行でデバッグする事も
必要だと思いますよ。

上に書いた様にパッチの適用だけで動かなくなる事も存在しますから。


コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2004-09-07 17:17
コード:
cout << old << "歳" << endl;

    return(0);



結果は期待した値が常に出ます。
ステップ実行で return(0); の中に入れないもんでしょうか。
NAO
ぬし
会議室デビュー日: 2001/10/24
投稿数: 1256
お住まい・勤務地: 神奈川のはずれから東京の下町
投稿日時: 2004-09-07 17:26
引用:

コブラさんの書き込み (2004-09-07 17:17) より:
コード:
cout << old << "歳" << endl;


return(0);



結果は期待した値が常に出ます。
ステップ実行で return(0); の中に入れないもんでしょうか。



coutで実行してもステップ実行だと最後まで行くと言う事で良いのかな?
つまりはreturnの中で何かしらの原因でセグメンテーションフォルトが起きていると。
そこまで行くと原因特定は難しいかもしれませんね。
おそらくバイナリレベルまで追いかけないといけないので…

一番最初の発言に書かれていた様に移植性を考慮して(標準関数)を使用してコードを書いた方が良いかもしれません。

そういう環境が準備出来るかどうか解りませんが。

Solaris側とLinuxのgccの環境を同じにした上で、どうなるかを見ないと
それ以上は何とも。

Solaris側に3.2.2を入れてコンパイル→実行→NGならばgcc仕様変更?
Redhat側でしか再現しないならRedhatのせい?
Redhatをクリーンインストール(OSオンリー+gccのみ)では?→再現しないなら他の物が影響?
じゃあ他のディストリビューションで実行したらOKならばRedhat特有の追加された他の仕様?

等々の切り分けが必要かと。

[ メッセージ編集済み 編集者: NAO 編集日時 2004-09-07 17:40 ]
ゆうじゅん
ぬし
会議室デビュー日: 2004/01/16
投稿数: 347
投稿日時: 2004-09-07 17:32
まちがっていたら申し訳ないのですが
コード:
unsigned int Age::Do(void)
{
    struct timeval *ts;
    struct tm *tm;

    gettimeofday(ts, NULL);
    tm = localtime((const time_t *)&ts->tv_sec);


の部分を

コード:
unsigned int Age::Do(void)
{
    struct timeval ts;
    struct tm *tm;

    gettimeofday(&ts, NULL);
    tm = localtime((const time_t *)ts.tv_sec);



と直したら動きませんか?
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2004-09-07 17:33
落ち着くところは、とどのつまり C の標準関数(笑)

オブジェクト指向で生産性アップと、OS・コンパイラ毎の移植作業で生産性ロスするのと
どっちを採るかな (プ
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2004-09-07 17:41
ゆうじゅんさん、助けて下さい。

コード:
struct timeval ts;
    struct tm *tm;

    gettimeofday(&ts, NULL);
    tm = localtime((const time_t *)ts.tv_sec);



この様に変更したところ、

$ ./a.out
誕生年(西暦)は? 2004
誕生月は?(1-12) 8
誕生日は?(1-31) 7
セグメンテーション違反です

年齢も出なくなってしまいました。。。
Yoshitake
会議室デビュー日: 2004/07/07
投稿数: 6
投稿日時: 2004-09-07 17:56
tm = localtime((const time_t *)ts.tv_sec);

tm = localtime((const time_t *)&(ts.tv_sec));

ではないでしょうか?

ちなみに、Solaris8 + gcc 3.2
では正常動作しました。

スキルアップ/キャリアアップ(JOB@IT)