全体表示

[ リスト | 詳細 ]

記事検索
検索

全14ページ

[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]

[ 次のページ ]

新人でもない新人君に「コンパイル通らないんですけど…」と尋ねられた時の話。

某解説書に記載されているサンプルコードを、サイトからDLし、ビルドするとエラー。
ものは、.h 3つと、.cpp 4つと、.c がひとつ。それと、Makefile。
makeすると、リンクでエラー。
どうやら、Cで書かれた関数がリンクに失敗している模様。
最初、プロトタイプ宣言と、関数定義の記述が食い違っているのかと思ったが、そうではない模様(前日に、double* と、double[]の違いで、リンクエラーになっていたのを訊かれたので)。

一見すると、どう見てもソースは合ってそう。一見すると。

問題のヘッダは↓(原文まま)
#ifndef MYLIB_H
#define MYLIB_H

#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>

#ifdef __cpluscplus
extern "C"{
#endif

void mySolidCylinder(double base, double height, int slices);

void myWireCylinder(double base, double height, int slices);


#ifdef __cpluscplus
}
#endif
#endif  // MYLIB_H
一見すると、ごくありふれたextern "C"の構文。
でも、よく見ると…
#include <math.h>

#ifdef __cpluscplus
extern "C"{
#endif

void mySolidCylinder(double base, double height, int slices);
?
#ifdef __cpluscplus
!

__cpluscplus

あんだーすこあ、あんだーすこあ、しーぷらす"しー"ぷらす!?

気付くのに随分と時間食ってしまいましたよ…
プリプロセッサは、コンパイル時になんも言わんしね…
あー、このことをorzって言うんだな…

開く コメント(40)

開く トラックバック(15)

[Boost]:1.33.0リリース

イメージ 1

Boost 1.33.0がリリースされた模様。
本家サイトもリニューアルされてます。
とりあえず。

開く コメント(0)

main関数は、グローバルスコープにいないとダメです。
名前空間の中に入れてしまうと、リンカでエラー(main()が無いよといわれる)になります。

ちなみに、mainは予約語ではないので、↓は合法(なだけで非推奨)。
#include <iostream>

namespace Foo
{
    struct main
    {
        enum { HOGE=99 };
    };

    int main()
    {
        std::cerr << "Foo::main()" << std::endl;
        return main::HOGE;
    }
}

int main( int argc, char* argv[] )
{
    int main = Foo::main();
    std::cerr << main << std::endl;
    if( argc-- )    ::main( argc, argv );  // ※1
    return 0;
}
でもなぜか、Borland C++ 5.5.1ではエラー
$ bcc32 -P test.cxx
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
test.cxx:
エラー E2178 test.cxx 18: 'main(int,char * *)' の VIRDEF が矛盾している
エラー E2120 test.cxx 19: プログラムの中からは main を呼び出せない(関数 main(int,char * *) )
エラー E2120 test.cxx 21: プログラムの中からは main を呼び出せない(関数 main(int,char * *) )
*** 3 errors in Compile ***
追記:
※1 規格では、main関数の再帰はやっちゃダメなんだそうな。まぁ、普通しないけど。

開く コメント(0)

空のクラスでも、以下のコードがコンパイル出来るのは、コンパイラがそれぞれのメンバ関数を自動的(暗黙のうち)に生成/定義してくれるからです。
class Foo
{
};

int main()
{
    Foo foo0;                   // デフォルトコンストラクタ Foo()
    const Foo   foo1(foo0);     // コピーコンストラクタ Foo( const Foo& )
    foo0 = foo1;                // 代入演算子 Foo& operator=( const Foo& )
    Foo*        pf = &foo0;     // アドレス演算子 Foo* operator&()
    const Foo*  cpf = &foo1;    // アドレス演算子 const Foo* operator&() const
    return 0;                   // デストラクタ ~Foo()
}
けれども、これらは善し悪しで意図せぬ動作を招くことが多々あります。
例えば、初期化には、必ず引数を取るコンストラクタでやって欲しい時や、オブジェクトのコピーを禁止したい場合など。
なので、使用するものは明示的に定義し、使用させないものは明示的に禁止するのが、明瞭かつお行儀の良いコードといえるでしょう。

禁止させる為の方法は、それらをprivateに宣言だけをして、定義はしないことです。
こうしておけば、たとえ使おうとしても、コンパイラがコンパイル時にエラーにしてくれます。


※アドレス演算子が問題になることはまず無いので、これは放置でよいでしょう。

参照:Effective C++ 27項、45項

開く コメント(0)

オブジェクトのエイリアシングを防ぐ為に、operator=()では自分自身への代入をチェックするようにしましょう。
自分自身かどうかの判定には、いくつかの方法があります。


operator==()による方法
Foo&	Foo::operator=( const Foo& rhs )
{
  if( *this == rhs )	return *this;  // operator==()があるものとして
  ・・・
  return *this;
}
汎用的に書ける


アドレスで識別する方法
Foo&	Foo::operator=( const Foo& rhs )
{
  if( this == &rhs )	return *this;
  ・・・
  return *this;
}
実装が簡単なのと、処理が速い


なんらかの識別子を返すメンバ関数を使う方法
クラスFooが、識別子を返すメンバ関数identity()を持っている場合
Foo&	Foo::operator=( const Foo& rhs )
{
  if( this->identity() == rhs.identity() )	return *this;
  ・・・
  return *this;
}
operator==()の変形版


参照:EffectiveC++:17項

開く コメント(0)

開く トラックバック(1)

全14ページ

[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]

[ 次のページ ]


.


プライバシー -  利用規約 -  メディアステートメント -  ガイドライン -  順守事項 -  ご意見・ご要望 -  ヘルプ・お問い合わせ

Copyright (C) 2019 Yahoo Japan Corporation. All Rights Reserved.

みんなの更新記事