小编Cha*_*l72的帖子

GCC内联汇编中的标签

在我正在进行的GCC内联汇编实验中,我遇到了一个关于标签和内联代码的新问题.

考虑以下简单的跳转:

__asm__
(
    "jmp out;"
    "out:;"
    :
    :
);
Run Code Online (Sandbox Code Playgroud)

除了跳转到out标签外,这没有任何作用.这样,这段代码编译得很好.但是如果你把它放在一个函数中,然后用优化标志进行编译,编译器就会抱怨:"错误:符号'out'已经被定义了".

似乎正在发生的事情是编译器每次内联函数时都会重复此汇编代码.这会导致标签out重复,从而导致多个out标签.

那么,我该如何解决这个问题呢?在内联装配中是否真的不可能使用标签?关于GCC内联汇编的教程提到:

因此,您可以将汇编放入CPP宏和内联C函数中,因此任何人都可以将其用作任何C函数/宏.内联函数非常类似于宏,但有时使用起来更干净.请注意,在所有这些情况下,代码将被复制,因此只应在该asm代码中定义本地标签(1:样式).

我试图找到有关这些"本地标签"的更多信息,但似乎无法找到与内联汇编有关的任何内容.看起来教程是说本地标签是一个数字后面跟冒号(比如1:),所以我尝试使用这样的标签.有趣的是,代码已编译,但在运行时它只是触发了分段错误.嗯...

那么任何建议,提示,答案......?

c c++ assembly gcc inline-assembly

38
推荐指数
2
解决办法
3万
查看次数

将typename关键字与模板函数参数一起使用

在C++中,typename需要关键字,因此编译器可以消除模板中嵌套类型和嵌套值之间的歧义.但是,在某些情况下,不存在歧义,例如派生类继承嵌套类类型时.

template <class T>
class Derived : public T::type
{ };
Run Code Online (Sandbox Code Playgroud)

这里typename关键字不是必需的,实际上甚至不允许.这是有道理的,因为上下文消除了歧义.在这里,T::type必须引用一个类型,因为你显然不能从一个值继承.

我认为同样的事情适用于函数模板参数.

template <class T>
void foo(const T::type& v)
{

}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,上下文清楚地表明T::type必须引用类型,因为函数参数不能是值.然而,编译器不接受这一点.它想要const typename T::type&.这似乎不一致.为什么语言允许在继承的上下文中隐式假设嵌套类型,而不是在函数参数的上下文中?在这两种情况下都不会有歧义,为什么需要typename一个而不是另一个呢?

c++ templates typename

28
推荐指数
2
解决办法
4473
查看次数

使用可变参数模板创建静态数组

stackoverflow上有一个答案(我似乎无法再找到它),它演示了如何在C++ 11中使用可变参数模板在编译时创建静态数组:

template <class T, T... args> 
struct array_
{
    static const T data[sizeof...(args)];
};

template <class T, T... args> 
const T array_<T, args...>::data[sizeof...(args)] = { args... };
Run Code Online (Sandbox Code Playgroud)

可以提供递归元函数以array_使用任意数量的参数进行实例化,然后将这些参数在编译时复制到内部数组中.这是创建元函数以在编译时生成常量数组的有用方法.

但是,一个问题是它依赖于类模板参数来获取填充数组的实际值.这导致一个主要限制:只有积分常数可以用作值模板参数.因此,您无法使用此技术生成自定义类型的数组.

我试着想办法解决这个限制,但不能提出任何建议.有没有办法让这种技术适用于非积分常数?

c++ templates variadic-templates c++11

25
推荐指数
2
解决办法
1万
查看次数

C++成员函数隐藏的原因

可能重复:
名称隐藏和脆弱的基本问题

我熟悉涉及成员函数隐藏的规则.基本上,具有与基类函数同名的函数的派生类实际上不会重载基类函数 - 它完全隐藏它.

struct Base
{
    void foo(int x) const
    {

    }
};

struct Derived : public Base
{
    void foo(const std::string& s) { }
};


int main()
{
    Derived d;
    d.foo("abc");
    d.foo(123); // Will not compile! Base::foo is hidden!
}
Run Code Online (Sandbox Code Playgroud)

所以,您可以通过using声明解决这个问题.但我的问题是,基类函数隐藏的原因是什么?这是标准委员会的"特征"还是"错误"?是否存在一些技术原因导致编译器在找不到匹配项时无法在Base类中查找匹配重载d.foo(123)

c++

22
推荐指数
3
解决办法
1万
查看次数

使用std :: pair或std :: tuple的移动语义

假设你想利用移动语义,但你的一个可移动类需要成为一部分std::pair.目的是创建一个函数,该函数返回一个std::pair可被视为右值并转发的函数.

但我无法看到如何做到这一点,除非对其std::pair自身进行内部更改,以使其了解移动语义.

请考虑以下代码:

struct Foo
{
 Foo() { }

 Foo(Foo&& f) { }

 private:

 Foo(const Foo& f) { } // do not allow copying
};

int main() 
{
 Foo f;
 std::pair<Foo, int> res = std::make_pair(f, 10); // fails due to private copy constructor
}
Run Code Online (Sandbox Code Playgroud)

问题是std::make_pair,除了std::pair构造函数本身之外,还需要两个对象并尝试制作它们的内部副本.这导致它尝试并调用复制构造函数.但在我的例子中,我希望能够新对移动res,并确保不会制作副本.我认为除非std::pair自己在内部定义了以下构造函数,否则这是不可能的:

pair(T1&& t1, T2&& t2) : first(std::move(t1)), second(std::move(t2))
Run Code Online (Sandbox Code Playgroud)

但它没有,至少在我使用的编译器上没有(gcc 4.3.2).这可能是因为我的编译器是简单地外的日期,而事实上新版本拥有这一举动感知构造.但是我对移动语义的理解目前有点不稳定,所以我不确定我是否只是在这里忽略了一些东西.那么,我是否正在努力实现,而不是实际重新实现std::pair?或者我的编译器是否已过时?

c++ move-constructor move-semantics c++11 std-pair

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

Numpy阵列广播规则

我在Numpy中理解阵列广播的规则时遇到了一些麻烦.

显然,如果你在两个相同尺寸和形状的数组上执行逐元素乘法,一切都很好.此外,如果您将多维数组乘以标量,它就可以工作.我明白了.

但是如果你有两个不同形状的N维阵列,我不清楚我究竟是什么广播规则.本文档/教程解释说:为了进行广播,操作中两个数组的尾随轴的大小必须相同,或者其中一个必须为1.

好的,所以我假设它是尾随轴,它们指的NM x N数组.那么,这意味着如果我尝试将两个二维数组(矩阵)乘以相同数量的列,它应该有效吗?除了它没有......

>>> from numpy import *
>>> A = array([[1,2],[3,4]])
>>> B = array([[2,3],[4,6],[6,9],[8,12]])
>>> print(A)
[[1 2]
 [3 4]]
>>> print(B)
[[ 2  3]
 [ 4  6]
 [ 6  9]
 [ 8 12]]
>>> 
>>> A * B
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape
Run Code Online (Sandbox Code Playgroud)

由于双方 …

python numpy numpy-broadcasting

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

Python 3中的PyEval_InitThreads:如何/何时调用它?(传奇继续令人作呕)

基本上似乎存在大量混淆/模糊性,而不PyEval_InitThreads()应该在什么时候被调用,以及需要哪些API调用.遗憾的是,官方Python文档非常模糊.关于这个主题的stackoverflow已经有很多问题了,事实上,我个人已经问了一个与这个问题几乎完全相同的问题,所以如果这个问题以复制方式结束,我不会特别感到惊讶; 但是考虑到这个问题似乎没有明确的答案.(可悲的是,我没有Guido Van Rossum的快速拨号.)

首先,让我们在这里定义问题的范围:我想做什么? 嗯...我想在C中编写一个Python扩展模块,它将:

  1. pthread在C中使用API的Spawn工作线程
  2. 从这些C线程中调用Python回调

好的,让我们从Python文档开始吧.在Python的3.2文档说:

void PyEval_InitThreads()

初始化并获取全局解释器锁.它应该在创建第二个线程或参与任何其他线程操作(如PyEval_ReleaseThread(tstate))之前在主线程中调用.在调用PyEval_SaveThread()或PyEval_RestoreThread()之前不需要它.

所以我的理解是:

  1. 产生线程的任何C扩展模块必须PyEval_InitThreads()在生成任何其他线程之前从主线程调用
  2. 调用PyEval_InitThreads锁定GIL

所以常识告诉我们,任何创建线程的C扩展模块都必须调用PyEval_InitThreads(),然后释放Global Interpreter Lock.好吧,看起来很简单.所以初步,所有的需要将以下代码:

PyEval_InitThreads(); /* initialize threading and acquire GIL */
PyEval_ReleaseLock(); /* Release GIL */
Run Code Online (Sandbox Code Playgroud)

看起来很简单......但不幸的是,Python 3.2文档PyEval_ReleaseLock已经弃用了.相反,我们应该使用PyEval_SaveThread以释放GIL:

PyThreadState*PyEval_SaveThread()

释放全局解释器锁(如果已创建并启用了线程支持)并将线程状态重置为NULL,则返回先前的线程状态(不是NULL).如果已创建锁,则当前线程必须已获取它.

呃......好吧,我想C扩展模块需要说:

PyEval_InitThreads();
PyThreadState* st = PyEval_SaveThread();
Run Code Online (Sandbox Code Playgroud)


实际上,这正是这个stackoverflow回答所说的.除非我在实践中尝试这样做,否则当我导入扩展模块时,Python解释器会立即出现错误.尼斯. …

python python-c-api python-c-extension python-3.x python-3.2

20
推荐指数
3
解决办法
6203
查看次数

兼容类型与严格别名规则

在C中将一种类型转换为另一种类型是一种常见的策略,依赖于C结构的布局具有某些保证的事实.像GLib这样的库依赖于它来实现面向对象的继承.基本上:

struct Base
{
  int x;
  int y;
};

struct Derived
{
  struct Base b;
  int z;
};
Run Code Online (Sandbox Code Playgroud)

这使得Base*指针可以分配给Derived对象的地址.

但我也知道" 严格别名 "规则,这是编译器隐含的假设,即不同类型的指针不能指向同一个地址.(这使编译器能够执行某些优化.)

那么,这两件事情如何协调?许多C库,包括Glib,CPython等,使用上述策略在类型之间进行转换.它们都只是用旗帜编译no-strict-aliasing吗?

c

18
推荐指数
1
解决办法
3470
查看次数

GCC内联汇编:约束

我很难理解角色约束在GCC内联汇编(x86)中的作用.我已经阅读了手册,它准确地解释了每个约束的作用.问题在于,即使我理解每个约束的作用,我也很少理解为什么要使用一个约束而不是另一个约束,或者含义可能是什么.

我意识到这是一个非常广泛的话题,所以一个小例子应该有助于缩小焦点.以下是一个简单的asm例程,它只添加了两个数字.如果发生整数溢出,则将值写入1输出C变量.

 int32_t a = 10, b = 5;
 int32_t c = 0; // overflow flag

 __asm__
 (
  "addl %2,%3;"        // Do a + b (the result goes into b)
  "jno 0f;"            // Jump ahead if an overflow occurred
  "movl $1, %1;"       // Copy 1 into c
  "0:"                 // We're done.

  :"=r"(b), "=m"(c)    // Output list
  :"r"(a), "0"(b)     // Input list
 );
Run Code Online (Sandbox Code Playgroud)

现在这个工作正常,除了我必须随意摆弄约束,直到我让它正常工作.最初,我使用了以下约束:

  :"=r"(b), "=m"(c)    // Output list
  :"r"(a), "m"(b)     // Input list
Run Code Online (Sandbox Code Playgroud)

请注意,我使用"m"约束而不是"0" b.这有一个奇怪的副作用,如果我用优化标志编译并调用该函数两次,由于某种原因,加法操作的结果也将被存储 …

c c++ gcc constraints inline-assembly

17
推荐指数
1
解决办法
4928
查看次数

std :: tuple中的Void类型

显然,你不能void在格式良好的程序中有一个类型的实例,所以类似下面的声明就不会编译:

std::tuple<void, double, int> tup;
Run Code Online (Sandbox Code Playgroud)

但是,只要我们严格处理类型而不是对象,似乎没有问题.例如,我的编译器(GCC)让我说:

typedef std::tuple<void, double, int> tuple_type;
Run Code Online (Sandbox Code Playgroud)

这对我来说很有意思,因为看起来使用C++ 0x我们可以用它std::tuple来执行许多早期需要boost::mpl库的元编程技巧.例如,我们可以使用std::tuple创建类型的向量.

例如,假设我们要创建表示函数签名的类型向量:

我们可以说:

template <class R, class... Args>
struct get_function_signature;

template <class R, class... Args>
struct get_function_signature<R(*)(Args...)>
{
    typedef std::tuple<R, Args...> type;
};
Run Code Online (Sandbox Code Playgroud)

这似乎有效,即使函数签名具有void类型,只要我们从未实际实例化实例get_function_signature<F>::type.

但是,C++ 0x对我来说仍然是新手,当然所有实现仍然有点实验性,所以我对此有点不安.我们真的可以std::tuple用作元编程的类型向量吗?

c++ tuples c++11

17
推荐指数
1
解决办法
3183
查看次数