如何在c#中进行按位相加?

How to make bitwise add in c#?

我正在尝试编写 PLC 地址生成器。但是,我需要进行位加法以找到下一个可用地址。

意味着如果我从地址 0.0 开始并添加 2 位,那么下一个空闲地址将是 0.3。它上升到 0.7 然后下一个地址是 1.0 到 1.7 然后 2.0 等等。

根据我添加到加法中的数据类型,应该计算下一个空闲地址。

例如,布尔值是一位。 0.1 -> 0.2 -> 0.3 等等 一个字节有 8 位,如果我添加一个字节,最后一个空闲地址是 0.4,下一个空闲地址应该是 2.0。

一个字有 16 位,所以 0.0 -> 2.0 -> 4.0 等等。

一个双字有 32 位,所以 0.0 -> 4.0 -> 8.0 等等。

我正在寻找 c# 中的实现,我可以在其中添加不同的类型作为输入,它会添加它并为我提供相应的地址并存储下一个内部空闲地址以供下一个操作使用。

例如:

    Type         Startaddress
1   Bool         0.0            (->0.1)
2   Bool         0.1            (->0.2)
3   Byte         1.0            (->1.7) as 8 bits are required
4   Bool         2.0            (->2.1) 
5   Word         3.0            (->4.7) as 16 bits are required
6   Double Word  5.0            (->8.7) as 32 bits are required

除了很多 if else 和循环之外,我知道如何实现它吗?我正在寻找一种优雅的重载运算符方法。

您可以将这些地址存储在一个 int 中 - 前 3 位中的低位部分,其余位中的其余部分,并从那里获取地址。这允许您对这些地址和数字进行正常的算术运算。如果地址是一个字符串,你可以这样做:

public static int ToIntAddress(this string str)
{
    var values = str.Split('.');
    int lower = int.Parse(values[1]);
    int higher = int.Parse(values[0]) << 3;
    return lower + higher;
}

public static string ToAddress(this int address) => $"{address >> 3}.{address & 0b0111}";

("3.0".ToIntAddress() + 15).ToAddress() // "4.7"
("5.0".ToIntAddress() + 31).ToAddress() // "8.7"
("0.4".ToIntAddress() + 7).ToAddress()  // "1.3"

您的唯一问题 "trick" 是位地址的 .0-.7 表示法,并且 C# 类型与您的规范中的类型不完全匹配。

我在这里展示的主要class地址在内部存储为位偏移量,并通过fAddress()方法提供整数和小数部分。

您的示例显示了字节边界对齐,但没有对齐字或双字——这就是我实现的。如果 PLC 关心,注释会显示如何以不同的方式执行此操作。

您需要添加代码以在 byte.bit 类型地址存储值。

using System;

namespace PLCAddress
{
    class Program
    {
        static void Main(string[] args)
        {
            PLCAddress a = new PLCAddress();
            float address;
            bool boolA = true;
            byte byteA = 7;
            ushort wordA = 65535;
            uint dblwordA = 4294967295;

            address = a.Store(boolA);
            Console.WriteLine(address.ToString());

            address = a.Store(boolA);
            Console.WriteLine(address.ToString());

            address = a.Store(byteA);
            Console.WriteLine(address.ToString());

            address = a.Store(boolA);
            Console.WriteLine(address.ToString());

            address = a.Store(wordA);
            Console.WriteLine(address.ToString());

            address = a.Store(dblwordA);
            Console.WriteLine(address.ToString());
        }
    }
    public class PLCAddress
    {
        protected uint _address;
        public PLCAddress()
        {
            _address = 0;
        }

        public float Store(bool b)
        {
            float rv = fAddress();
            _address += 1;
            return rv;
        }
        public float Store(byte b)
        {
            float rv = fAddress(8);
            _address += 8;
            return rv;
        }
        public float Store(ushort b)
        {
            float rv = fAddress(8); // use fAddress(16) if words need to be on word boundaries
            _address += 16;
            return rv;
        }
        public float Store(uint b)
        {
            float rv = fAddress(8); // use fAddress(32) if double words need to be on double word boundaries
            _address += 32;
            return rv;
        }

        protected float fAddress()
        {
            return (float)Whole + (float)Fraction / 10;
        }

        protected float fAddress(uint alignment)
        {
            uint roundup = alignment - 1;
            uint mask = ~roundup;
            uint AlignedAddress = _address + roundup;
            AlignedAddress = AlignedAddress & mask;
            _address = AlignedAddress;
            return fAddress();
        }
        protected uint Whole
        {
            get { return _address / 8; }
        }
        protected uint Fraction
        {
            get { return _address % 8;  }
        }
    }
}

我个人更喜欢面向对象的方法:

public class MemoryManager
{
    private int _dataSize = 0;

    public enum DataTypes
    {
        Bool = 1,
        Byte = 8,
        Word = 16,
        DWord = 32
    }
    public MemoryLocation Add(DataTypes type)
    {            
        var address = GetCurrentAddress();
        _dataSize += (int)type;
        return address;
    }

    private MemoryLocation GetCurrentAddress()
    {
        int currentByteLocation = _dataSize / 8;
        int currentBitLocation = _dataSize % 8;            
        return new MemoryLocation(currentByteLocation, currentBitLocation);
    }        
}

public class MemoryLocation
{
    public MemoryLocation(int byteLocation, int bitIndex)
    {
        ByteLocation = byteLocation;
        BitIndex = bitIndex;            
    }
    public int ByteLocation { get; private set; }
    public int BitIndex { get; private set; }        
    public override string ToString()
    {
        return string.Format("[{0},{1}]", ByteLocation, BitIndex);
    }
}

我很快就完成了这个,但您可以使用其他更简化的方法来生成下一个地址。

你可以使用这个:

public int BitWiseAdd()
{
            int FirstNumber = 50;
            int SecondNumber = 60;
            while (SecondNumber !=0)
            {

                int carry = FirstNumber & SecondNumber;
                FirstNumber = FirstNumber ^ SecondNumber;
                SecondNumber = carry << 1;
            }
            return FirstNumber;


}