@Ultrakayo

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

C言語の構造体をC#の構造体に移植したい

解決したいこと

C で作成したファイルをC#に移植する作業をしていますが
苦戦しております。
例)
C
work.h
struct INFO {
unsigned short id;
unsigned short No;
unsigned char error;
unsigned char rsv1;
};
sample.c
struct INFO info[64];

main.c
fo(int i=0;i<64;i++)
{
info[i].id=0xfe04;
info[i].No=i;
......
}
のようなことを
 C#で実現しようとすると
work.cs
public static struct INFO {
public static UInt16 id;
public static UInt16 No;
public static Byte error;
public static Byte rsv1;
};

main.cs
INFO[] info[64]=new INOFO(); // ??
のようになると思いますが
 このinfo[0].idを他のcsで
使用することができません。
※ 実際は info配列で ファイル操作や
 データ操作を行いたいのです
 
解決方法を教えて下さい。

0 likes

3Answer

このinfo[0].idを他のcsで使用することができません。

「他のcs」とは何でしょう?


【追記】

他のCSとは 同じnamespace内の他のxxx,csファイルという意味です。

work.cs ファイルで定義した構造体を、main.cs ファイルの中の main エントリーポイントで初期化して、XXX.cs ファイルの中のコードで使いたいということですか?

もしそうであれば、以下のようにしてやりたいことは実現できませんか? 以下は Visual Studio 2022 で作成した .NET 9.0 のコンソールアプリの例です。

Work.cs

namespace ConsoleApp2
{
    public struct INFO
    {
        public UInt16 id;
        public UInt16 No;
        public Byte error;
        public Byte rsv1;
    };
}

Program.cs (質問者さんの main.cs に該当)

namespace ConsoleApp2
{
    public static class Program
    {
        public static INFO[]? infoArray;

        static void Main(string[] args)
        {
            infoArray = new INFO[2];
            infoArray[0] = new INFO { id = 1, No = 10, error = 0, rsv1 = 1 };
            infoArray[1] = new INFO { id = 2, No = 20, error = 0, rsv1 = 1 };

            XXX xxx = new XXX();
            xxx.WriteValues();
        }
    }
}

XXX.cs

namespace ConsoleApp2
{
    public class XXX
    {
        public void WriteValues()
        {
            foreach (INFO info in Program.infoArray!)
            {
                Console.WriteLine($"id: {info.id}, No: {info.No}, error: {info.error}, rsv1: {info.rsv1}");
            }
        }
    }
}

実行結果

result.jpg

1Like

Comments

  1. @Ultrakayo

    Questioner

    早速の投稿ありがとうございます。
    他のCSとは 同じnamespace内の他のxxx,csファイルという意味です。
    BulderC++では class HostForm : public TForm 内で INFO info[64];
    のように class HostForm内ではinfo[0]=0;がつかえたのですが
    C#では その手法は使えないということでしょうか? 

  2. @Ultrakayo

    Questioner

    追補: public struct Info
    {
    public static UInt16[] id = new UInt16[64];
    public static UInt16[] No = new UInt16[64];
    public static Byte[] Erro = new Byte[64];

    のようにすることもできますが、メモリー内が id[0],id[1]... No[0],No[1]...の
    ようになってしまいます id[0],No[0],Erro[0]..id[1],No[1],Erro[1]...
    のような 感じにしたいのです。

  3. 他のCSとは 同じnamespace内の他のxxx,csファイルという意味です。

    work.cs ファイルで定義した構造体を、main.cs ファイルの中の main エントリーポイントで初期化して、XXX.cs ファイルの中のコードで使いたいということですか?

    もしそうであれば、以下のようにしてやりたいことは実現できませんか? 以下は Visual Studio 2022 で作成した .NET 9.0 のコンソールアプリの例です。

    Work.cs

    namespace ConsoleApp2
    {
        public struct INFO
        {
            public UInt16 id;
            public UInt16 No;
            public Byte error;
            public Byte rsv1;
        };
    }
    
    

    Program.cs (質問者さんの main.cs に該当)

    namespace ConsoleApp2
    {
        public static class Program
        {
            public static INFO[]? infoArray;
    
            static void Main(string[] args)
            {
                infoArray = new INFO[2];
                infoArray[0] = new INFO { id = 1, No = 10, error = 0, rsv1 = 1 };
                infoArray[1] = new INFO { id = 2, No = 20, error = 0, rsv1 = 1 };
    
                XXX xxx = new XXX();
                xxx.WriteValues();
            }
        }
    }
    

    XXX.cs

    namespace ConsoleApp2
    {
        public class XXX
        {
            public void WriteValues()
            {
                foreach (INFO info in Program.infoArray!)
                {
                    Console.WriteLine($"id: {info.id}, No: {info.No}, error: {info.error}, rsv1: {info.rsv1}");
                }
            }
        }
    }
    

    実行結果

    result.jpg

  4. @Ultrakayo

    Questioner

    ありがとうございます。試してみます。

C#のトップレベルステートメントは暗黙的にエントリポイントとしてメソッドを生成するので,そのままでは変数を外から見ることはできません.

なのでstaticにするか,本当にその配列をどこからでも見える位置に置いておく必要があるか検討する必要はあります.

1Like

Comments

  1. そもそも例示されたCとC#のソースだと意味が違ってきますね.
    こちらどうぞ.

  2. @Ultrakayo

    Questioner

    早速の投稿ありがとうございます。
    ちょっと 検討してみます。
    ご教示ありがとうございました。

  3. @Ultrakayo

    Questioner

    そもそも例示されたCとC#のソースだと意味が違ってきますね.
    こちらどうぞ.
    C言語の方は H8(ルネサス)で作成したものでメモリーに直接書き込んでいます
    その意味では C#のほうは ちがうのですが.....
     

  4. C言語の方は H8(ルネサス)で作成したものでメモリーに直接書き込んでいます
    その意味では C#のほうは ちがうのですが.....

    そこではなくて,そもそもメンバをstaticにしてしまってるのでvalue.idというようにインスタンス的に使うことができません.

  5. @Ultrakayo

    Questioner

    そうなんですか Staticは 万能かと 思いました。

  6. @Ultrakayo

    Questioner

    メンバ変数にstaticをつけた場合、その変数がメモリ上のどこに配置されるかが固定される。メモリ上の位置が固定されるということはどこからでもこの変数にアクセスできるということです。と 記述されていましたので....

  7. @Ultrakayo

    Questioner

    public struct INFO {
    public UInt16 id;
    public UInt16 No;
    public Byte error;
    public Byte rsv1;};
    INFO[] info = new INFO[64];にしたら
    info[0].id=0が可能になります。
    Staticを使うと 初期化しなくても 直接
    制御できると 書いてあったので...
    どうにか 使えそうです。
    ありがとうございました。
      

Comments

  1. @Ultrakayo

    Questioner

    そうですが、色々調べても あまり良い方法が 見つからなくて....
      

  2. global usingでいいのではないでしょうか
    これはプロジェクト全体で名前空間を共有するための宣言子です
    まず構造体と静的メンバを用意します

    public struct INFO {
    	public UInt16 id;
    	public UInt16 No;
    	public Byte error;
    	public Byte rsv1;
    }
    
    namespace INFODesigner{
    	public class INFOManager{
    		public static INFO[] info=[new(),new(),new()];
    	}
    }
    

    続いて名前空間を宣言します
    using staticを使用することで、静的メンバに対して完全修飾名を省略できます
    以下は使用例です

    global using static INFODesigner.INFOManager;
    using System;
    					
    public class Program
    {
    	public static void Main()
    	{
    		Console.WriteLine(info[0].id);
    	}
    }
    
    0
    

    global using staticで静的メンバのプロジェクト内共有を宣言します
    global using宣言がまとめられた.csファイルもあるので、そちらにglobal using static 名前空間.クラス名;のフォーマットで宣言を追加するといいでしょう

    これで期待された動作になるはずです

  3. 質門者さんは C 言語では extern を使って異なるファイル間で変数を共有していて、C# 言語でそれに代わる解決方法を知りたいというのが質問の趣旨ではないかと想像しています。

    そうだとすると、global using では解決できないと思うのですが、いかがですか?

  4. @Ultrakayo

    Questioner

    @blonz3977さんありがとうございます。
    早速 試してみたいと 存じます。

  5. extern を使って異なるファイル間で変数を共有していて

    であればなおさらglobal usingが適格かと思うのですが、ファイル間共有の他にも用途があるのでしょうか?

    externはライブラリとのリンクを想定するキーワードですから、そうであればC#では.csproj

    <ItemGroup>
        <Reference Include=“.dllPath”>
        </Reference>
    </ItemGroup>
    

    を設けて、改めてglobal usingを加えることで同等の操作になるはずです
    また名前空間はライブラリの内外問わず拡張可能なので、後から新しいグローバル変数のようなものを新しいクラスの静的メンバとして同一名前空間内に追加構築できます

    グローバル領域はC#から見れば静的領域の一部ですから、staticメンバとして扱うべきかと思います

  6. @Ultrakayo

    Questioner

    @blonz3977さん C#7.3ではエラーになります。C#10.0以上でないとダメみたいです。
    開発環境Windows10でVisual Stadio 2022ですが 対象プラットフォームは Linux上なので AnyCPUで作成しております。言語バージョンを選択できないみたいです。  

  7. 尚「名前空間を共有する」とは、以下のように定義を分割することを指します

    info.cs
    public struct INFO {
    	public UInt16 id;
    	public UInt16 No;
    	public Byte error;
    	public Byte rsv1;
    }
    
    namespace INFODesigner{
    	public class INFOManager{
    		public static INFO[] info=[new(),new(),new()];
    	}
    }
    
    global.cs
    global using static INFODesigner.INFOManager;
    global using System;
    
    Program.cs
    public class Program
    {
    	public static void Main()
    	{
    		Console.WriteLine(info[0].id);
    	}
    }
    

Your answer might help someone💌