小编Min*_*s97的帖子

什么是"特殊班级"?

在未能获得类似以下内容的编译之后:

public class Gen<T> where T : System.Array
{
}
Run Code Online (Sandbox Code Playgroud)

有错误

约束不能是特殊的类`System.Array'

我开始疑惑,究竟什么 "特殊班级"?

当人们System.Enum在泛型约束中指定时,人们似乎经常会遇到同样的错误.我得到了相同的结果System.Object,System.Delegate,System.MulticastDelegateSystem.ValueType也.

还有更多吗?我在C#中找不到关于"特殊类"的任何信息.

此外,什么如此特殊的,我们不能把它们作为一个泛型类型约束类?

c# generics class generic-constraints

113
推荐指数
7
解决办法
6505
查看次数

Lambda参数在后面的范围内访问字段时与类字段冲突

在名称方面我的想象力很弱,所以我经常发现自己在代码中重用了标识符.这导致我遇到这个特定的问题.

这是一些示例代码:

public delegate void TestDelegate(int test);

public class Test
{
    private int test;

    private void method(int aaa)
    {
        TestDelegate del = test => aaa++;

        test++;
    }

    public static void Main()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是编译错误(由ideone输出):

prog.cs(11,3): error CS0135: `test' conflicts with a declaration in a child block
prog.cs(9,22): (Location of the symbol related to previous error)
Compilation failed: 1 error(s), 0 warnings
Run Code Online (Sandbox Code Playgroud)

第11 test++行包含第9行包含lambda.

顺便说一下,Visual Studio 2013给出了不同的错误:

'test' conflicts with the declaration 'Namespace.Test.test'
Run Code Online (Sandbox Code Playgroud)

该错误仅在第11行的增量处发生.

如果我注释掉第9行(lambda)或第11行(增量),代码会成功编译.

这个问题让我感到惊讶 - …

c# lambda field class increment

21
推荐指数
2
解决办法
695
查看次数

在FSharp.Core中没有记录`when`关键字用法

寻找有关内联函数的静态解析类型参数的信息,我偶然发现了FSharp.Core 中各种原始运算符的定义:

let inline (+) (x: ^T) (y: ^U) : ^V = 
     CheckedAdditionDynamic<(^T),(^U),(^V)>  x y 
     when ^T : int32       and ^U : int32      = (# "add.ovf" x y : int32 #)
     when ^T : float       and ^U : float      = (# "add" x y : float #)
     // <snip>
     when ^T : ^T = ((^T or ^U): (static member (+) : ^T * ^U -> ^V) (x,y))
Run Code Online (Sandbox Code Playgroud)

从上面的代码片段中可以看出,when关键字的使用格式为:when expr1 = expr2适用于各种内置类型.我猜这是某种编译器相当于"如果T = int使用opcode add.ovf,否则如果......,否则就这样做". …

f#

20
推荐指数
1
解决办法
466
查看次数

为什么AtomicInteger和类似类的getAndSet()中有一个循环?

出于何种目的,在此代码中使用循环

public final int getAndSet(int newValue) {
    for (;;) {
        int current = get();
        if (compareAndSet(current, newValue))
            return current;
    }
}
Run Code Online (Sandbox Code Playgroud)

java concurrency

19
推荐指数
2
解决办法
1052
查看次数

将指向内存缓冲区的指针转换为指向VLA的指针

在C中,我相信以下程序是有效的:将指向已分配内存缓冲区的指针转换为如下数组:

#include <stdio.h>
#include <stdlib.h>

#define ARRSIZE 4

int *getPointer(int num){
    return malloc(sizeof(int) * num);
}

int main(){
    int *pointer = getPointer(ARRSIZE);
    int (*arrPointer)[ARRSIZE] = (int(*)[ARRSIZE])pointer;

    printf("%d\n", sizeof(*arrPointer) / sizeof((*arrPointer)[0]));

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

(这输出4).

但是,在C99中,使用VLA进行此操作是否安全?

    int arrSize = 4;
    int *pointer = getPointer(arrSize);
    int (*arrPointer)[arrSize] = (int(*)[arrSize])pointer;

    printf("%d\n", sizeof(*arrPointer) / sizeof((*arrPointer)[0]));

    return 0;
Run Code Online (Sandbox Code Playgroud)

(也是输出4).

根据C99标准,这是否合法?

如果它是合法的,那将是很奇怪的,因为这意味着VLA有效地启用动态类型创建,例如,类型的类型type(*)[variable].

c arrays pointers c99

12
推荐指数
1
解决办法
681
查看次数

指定类本身的泛型类的基类约束

昨天,我向朋友们解释了C#的通用限制.在展示where T : CLASSNAME约束时,我掀起了这样的事情:

public class UnusableClass<T> where T : UnusableClass<T>
{
    public static int method(T input){
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

并且看到它编译真的很惊讶.然而,经过一番思考之后,我认为从编译器的角度来看它是完全合法的 - UnusableClass<T>与其他任何可用于此约束的类一样多.

然而,这留下了几个问题:如何使用这个类?是否有可能

  1. 实例化吗?
  2. 继承吗?
  3. 调用它的静态方法int method

如果是的话,怎么样?

如果其中任何一种可能,那么它的类型T是什么?

c# generics type-parameter generic-constraints

11
推荐指数
3
解决办法
1286
查看次数

与第一个成员共享的结构联盟

我一直在研究在C11前C中实现结构"多态"的非传统方式.假设我们有2个结构:

struct s1 {
    int var1;
    char var2;
    long var3;
};

struct s2 {
    int var1;
    char var2;
    long var3;
    char var4;
    int var5;
};
Run Code Online (Sandbox Code Playgroud)

在大多数编译器中,我们可以安全地在指向两者的指针之间进行转换,然后在没有填充的情况下访问公共的第一个成员.但是,这不是标准化的行为.

现在,我在C标准中找到了以下C89行:

为了简化联合的使用,我们做了一个特殊的保证:如果一个联合包含几个共享一个共同初始序列的结构,并且如果联合对象当前包含这些结构中的一个,则允许检查任何共同的初始部分.他们 如果相应的成员具有一个或多个初始成员的序列的兼容类型,则两个结构共享共同的初始序列.

它还说明了以下内容:

指向联合对象的指针(适当地强制转换)指向其每个成员(或者如果成员是位字段,则指向它所在的单元),反之亦然.

现在,如果我创建这两个结构的联合:

union s2_polymorphic {
    struct s1 base;
    struct s2 derived;
};
Run Code Online (Sandbox Code Playgroud)

并以这种方式使用它:

union s2_polymorphic test_s2_polymorphic, *ptest_s2_polymorphic;
struct s2 *ptest_s2;
struct s1 *ptest_s1;

ptest_s2_polymorphic = &test_s2_polymorphic;

ptest_s2 = (struct s2*)ptest_s2_polymorphic;

ptest_s2->var1 = 1;
ptest_s2->var2 = '2';

ptest_s1 = (struct s1*)ptest_s2;

printf("ptest_s1->var1 = %d\n", ptest_s1->var1);
printf("ptest_s1->var2 = %c\n", ptest_s1->var2);
Run Code Online (Sandbox Code Playgroud)

编译并运行良好,并在gcc(GCC)4.8.3 …

c struct pointers unions

10
推荐指数
1
解决办法
1516
查看次数

可变修改类型兼容性及其安全隐患

我对C99的可变修改型系统感兴趣.这个问题的灵感来自于这个问题.

检查这个问题的代码,我发现了一些有趣的东西.考虑以下代码:

int myFunc(int, int, int, int[][100]);

int myFunc(int a, int b, int c, int d[][200]) {
    /* Some code here... */
}
Run Code Online (Sandbox Code Playgroud)

这显然不会(也不会)编译.但是,这段代码:

int myFunc(int, int, int, int[][100]);

int myFunc(int a, int b, int c, int d[][c]) {
    /* Some code here... */
}
Run Code Online (Sandbox Code Playgroud)

编译甚至没有警告(在gcc上).

这似乎意味着可变修改的阵列类型与任何非可变修改的阵列类型兼容!

但那还不是全部.您期望一种可变修改类型至少可以使用哪个变量来设置其大小.但它似乎没有这样做!

int myFunc(int, int b, int, int[][b]);

int myFunc(int a, int b, int c, int d[][c]) {
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

也编译没有任何错误.

所以,我的问题是:这是正确的标准化行为吗?

此外,如果一个可变修改的数组类型真的与任何具有相同维度的数组兼容,那么这不会意味着令人讨厌的安全问题吗?例如,请考虑以下代码:

int myFunc(int a, int b, int c, int …
Run Code Online (Sandbox Code Playgroud)

c gcc c99 variable-length-array

10
推荐指数
1
解决办法
118
查看次数

easy struct inheritance&pseudo-polymorphism vs strict aliasing

如果有人回答我的问题,请不要告诉我使用C++.

所以,我在C中创建了一个使用面向对象方法的小型库.我选择在C中使用两种主要的继承方法中较不常见的方法:将基类型的成员复制到派生类型的开头.像这样的东西:

struct base {
  int a;
  int b;
  char c;
};

struct derived {
  int a;
  int b;
  char c;
  unsigned int d;
  void (*virtual_method)(int, char);
};
Run Code Online (Sandbox Code Playgroud)

这种方法不如另一种方法(基类型的实例作为派生类型的第一个成员)受欢迎,因为

  1. 从技术上讲,没有标准保证基础和派生结构的第一个共同成员将具有相同的抵消.但是,除了其中一个结构被打包而另一个结构没有被打包的情况之外,它们将在大多数(如果不是全部)已知编译器上具有相同的偏移量.
  2. 这种方法最严重的缺陷:它违反了严格的别名.将指向派生结构的指针强制转换为其基类型然后解除引用指针在技术上是未定义的行为.

但是,与其他方法相比,它也有其优点:

  1. 更少详细:访问已继承的派生结构的成员与访问尚未继承的结构相同,而不是转换为基类型,然后访问所需的成员;
  2. 这实际上是真正的继承而不是构成 ;
  3. 虽然可能需要一些预处理器滥用,但它与其他方法一样容易实现;
  4. 我们可以得到一个实际多重继承的半生不熟的形式,我们可以从几个基类型继承,但只能转换为其中一个.

我一直在寻找使我的库编译和使用强制执行严格别名(如gcc)的编译器正确工作的可能性,而无需用户手动关闭它.以下是我研究过的可能性:

  1. 工会.遗憾的是,由于以下几个原因,这些是禁忌:

    1. 详细程度回归!要遵循通过联合访问2个结构的第一个共同成员的标准规则,必须(从C99开始)明确使用联合来访问第一个共同成员.我们需要特殊的语法来访问联合中每种类型的成员!
    2. 空间.考虑一个继承层次结构.我们有一个类型,我们希望能够从每个派生类型转换为.我们希望为每种类型做到这一点.我看到的唯一可行的联合使用解决方案是整个层次结构的并集,它必须用于将派生类型的实例转换为基类型.它必须与整个层次结构中派生类型最多的一样大......
  2. 使用memcpy而不是直接解除引用(如此).这看起来是个不错的解决方案.但是,函数调用会产生开销,是的,再一次,冗长.据我所知,memcpy也可以通过将指向结构的指针强制转换为指针char然后解除引用来手动完成,如下所示:(member_type)(*((char*)(&struct_pointer->member))) = new_value;Gah,再次详述.好吧,这可以用宏包裹.但是,如果我们将指针转换为指向不兼容类型的指针,然后将其转换为char*并取消引用它,那么它仍然可以工作吗?像这样:(member_type)(*((char*)(&((struct incompatible_type*)struct_pointer)->member))) = new_value;

  3. 声明我们将要转换为的所有类型实例 …

c inheritance struct pointers strict-aliasing

6
推荐指数
1
解决办法
604
查看次数

为什么lambda表达式在方法终止后保留封闭范围变量值?

我的印象是C#中的lambda表达式上下文包含对其中使用的父函数作用域的变量的引用.考虑:

public class Test
{
    private static System.Action<int> del;

    public static void test(){
        int i = 100500;
        del = a => System.Console.WriteLine("param = {0}, i = {1}", a, i);
        del(1);

        i = 10;
        del(1);

    }

    public static void Main()
    {
        test();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出

param = 1, i = 100500
param = 1, i = 10
Run Code Online (Sandbox Code Playgroud)

但是,如果这是真的,则以下内容将是非法的,因为lambda上下文将引用超出范围的局部变量:

public class Test
{
    private static System.Action<int> del;

    public static void test(){
        int i = 100500;
        del = a => System.Console.WriteLine("param = {0}, …
Run Code Online (Sandbox Code Playgroud)

c# lambda

6
推荐指数
1
解决办法
822
查看次数