谷歌严格别名的第一个结果之一就是这篇文章
http://dbp-consulting.com/tutorials/StrictAliasing.html
我注意到的一个有趣的事情是:http://goo.gl/lPtIa5
uint32_t swaphalves(uint32_t a) {
uint32_t acopy = a;
uint16_t* ptr = (uint16_t*)&acopy;
uint16_t tmp = ptr[0];
ptr[0] = ptr[1];
ptr[1] = tmp;
return acopy;
}
Run Code Online (Sandbox Code Playgroud)
被编译为
swaphalves(unsigned int):
mov eax, edi
ret
Run Code Online (Sandbox Code Playgroud)
由GCC 4.4.7.任何比这更新的编译器(文章中提到的4.4所以文章没有错)都没有实现该功能,因为它可以使用严格别名.这是什么原因?它实际上是GCC中的错误还是GCC决定放弃它,因为许多行代码是以产生UB的方式编写的,或者它只是一个持续多年的编译器回归...而Clang也没有优化它.
2011年标准明确规定......
6.7.6.2数组声明符
- 如果size是一个不是整数常量表达式的表达式:如果它出现在函数原型范围的声明中,则将其视为替换为
*; 否则,每次评估它时,其值应大于零.可变长度数组类型的每个实例的大小在其生命周期中不会改变.如果size表达式是运算sizeof符操作数的一部分,并且更改size表达式的值不会影响运算符的结果,则无法指定是否计算size表达式.
这是设计,但以下代码似乎是合理的.
size_t vla(const size_t x) {
size_t a[x];
size_t y = 0;
for (size_t i = 0; i < x; i++)
a[x] = i;
for (size_t i = 0; i < x; i++)
y += a[i % 2];
return y;
}
Run Code Online (Sandbox Code Playgroud)
Clang似乎为它生成合理的x64程序集(没有优化).显然索引零长度VLA没有意义,但访问超出边界会调用未定义的行为.
为什么零长度数组未定义?
不仅仅是一般情况,我有一个非常具体的例子:在GSL(GNU科学库)中,使用的主要函数类型(为了执行集成,根查找,...)是gsl_function,它有一个属性function类型是 double(*)(double, void *)
说我想创建一个gsl_function从double a_squared(double a) {return a*a};.我a__squared的类型是double(*)(double)我想创建一个convert函数接受参数(double(*)(double) f)并返回一个double(*)(double, void *)满足的类型的对象convert(f)(double a, NULL) == f(a)
但经过一些研究,似乎我无法在我的convert函数中定义另一个函数.如何进行 ?
众所周知,一些没有非平凡复制的小结构,没有非平凡的dtor在寄存器中传递.
引用ARM程序调用标准:
大于32位的基本类型可以作为参数传递给函数调用,或者作为函数调用的结果返回.当这些类型在核心寄存器中时,以下规则适用:双字大小类型在两个连续寄存器中传递(例如,r0和r1,或r2和r3).寄存器的内容就好像该值是通过单个LDM指令从存储器表示加载的.
事实上,我可以轻松地用铿锵声证实这一点.然而,gcc为这样一个简单的代码片段发出了大量的内存加载和存储:
struct Trivial {
int i1;
int i2;
};
int foo(Trivial t)
{
return t.i1 + t.i2;
}
Run Code Online (Sandbox Code Playgroud)
$ clang++ arm.cpp -O2 -mabi=aapcs -c -S && cat arm.s
add r0, r0, r1
bx lr
Run Code Online (Sandbox Code Playgroud)
$ g++ arm.cpp -O2 -mabi=aapcs -c -S && cat arm.s
sub sp, sp, #8
add r3, sp, #8
stmdb r3, {r0, r1}
ldmia sp, {r0, r3}
add r0, r0, r3
add sp, sp, #8
bx lr
Run Code Online (Sandbox Code Playgroud)
我正在使用由ArchlinuxARM发行版提供的gcc和clang,在raspberry pi 2(gcc 5.2)上运行,但我也用基于gcc的交叉编译器再现它.
当我使用fprintf:
fprintf(somefile,"%c",'\n');
Run Code Online (Sandbox Code Playgroud)
它将"\ r \n"打印到文件中.我如何打印'\n'?
我正在写一个二进制文件.上面的代码仅用于调试.
这个问题几乎说明了一切。根据的手册页getrusage(),它返回:
struct timeval ru_utime; /* user CPU time used */
struct timeval ru_stime; /* system CPU time used */
Run Code Online (Sandbox Code Playgroud)
根据的手册页clock_gettime(),它返回:
CLOCK_THREAD_CPUTIME_ID (since Linux 2.6.12)
Thread-specific CPU-time clock.
Run Code Online (Sandbox Code Playgroud)
那么,(特定于线程的)“使用的用户/系统CPU时间”与特定于线程的CPU时间时钟有何不同?
显然,我之所以问是因为,在从自定义RTOS移植到Linux的应用程序中,我看到了两者之间的差异。该应用程序具有通过tick()和tock()功能实现的内部配置文件功能。我一直在研究这个问题,因此我将应用程序的一部分退化为:
tick()
// code commented out
tock()
Run Code Online (Sandbox Code Playgroud)
该tick()函数记录运行时间,tock()函数记录运行时间,计算两者之间的增量,并报告该增量。当我实现tick()并tock()使用时getrusage(),我得到的大部分为0,偶尔会有1000us或10000us的值(根据我是否将内核配置为1kHz或100Hz操作)。当我实现tick()并tock()使用时clock_gettime(),我得到的值以13us为中心(偶尔会出现75us或100us的奇异偏移,但稍后再讨论)。
我尝试在内核和VIRT_CPU_ACCOUNTINGand / or的各种组合中启用高分辨率计时器VIRT_CPU_ACCOUNTING_GEN。我看到的唯一效果是,报告的非零值getrusage()从1000us更改为以1000us为中心的更高精度的范围。
我最终转而使用clock_gettime()并获得了更可信的结果,但是我想知道为什么这两个系统调用存在,以及为什么它们的行为如此不同。所以我想我应该问一些专家。
我有以下递归函数输出部分组合:
void comb(string sofar, string rest, int n) {
string substring;
if (n == 0)
cout << sofar << endl;
else {
for (size_t i = 0; i < rest.length(); i++) {
substring = rest.substr(i + 1, rest.length());
comb(sofar + rest[i], substring, n - 1);
}
}
}
Run Code Online (Sandbox Code Playgroud)
如此称呼:
comb("", "abcde", 3);
Run Code Online (Sandbox Code Playgroud)
通过部分组合,我的意思是它使用n个选项和r个元素(而不是n个选项,n个元素).
但是,我想考虑元素的顺序(即排列).我可以找到很多完全排列的算法,但不是部分的.
我有一些列表需要迭代,有时从头到尾,有时从头到尾。此列表从未修改过,我将对其进行多次遍历。当我要从头到尾进行迭代时,我想避免在O(n)中反转列表的操作。
是否有某种允许的数据结构?
我以为C#中的(双重)LinkedList实现允许这种行为很简单(通过保留列表开头的内部引用),但是我不认为它是通过这种方式实现的。如果我错了,可以提供一个链接吗?
我是Haskell的新手,只是偶然发现了这个问题.我试图找出解释,但我没有足够的经验与Haskell类型确定.
功能:
mystery :: Int -> Int -> Float -> Bool
mystery x y z = not ((x==y) && ((fromIntegral y) == z ))
Run Code Online (Sandbox Code Playgroud)
表现得像它似乎会.它基本上检查值是否都不相等,但是从a进行类型转换Integral y以确保它可以与之进行比较z
如果这是真的,那么为什么:
case1 = do
if mystery 1 1 1.00000001 -- a very small number
then putStrLn "True"
else putStrLn "False"
Run Code Online (Sandbox Code Playgroud)
打印错误(即,值全部相等,所以1 == 1 == 1.00000001),而:
case2 = do
if mystery 1 1 1.0000001 -- a larger number
then putStrLn "True"
else putStrLn "False"
Run Code Online (Sandbox Code Playgroud)
打印真的吗?(即.值并非全部相等)
我知道它可能与精度有关,但我不明白.任何帮助是极大的赞赏.
我正在用 C 编写我自己的小外壳,或者至少我今天要开始。我想实现三个功能。
remove file1为此我需要哪些系统调用?只需打开文件并删除其内容,或者除了使用之外是否还有删除文件的系统调用rm?
mycopy source destination为此,我正在考虑让一个缓冲区并打开 file1 读入缓冲区并写出到 file2 但我不知道如何将它实际放入代码中,如果有人可以将一个小例子放在一起,这对很多人有帮助。
move source destination这只是实现复制和删除吗?
我的主要问题是使用 argv[] 参数我从来没有这样做过,所以它对我来说是新的。