在C和C++中未定义有符号整数溢出.但是在单个字段中有符号整数溢出__m128i呢?换句话说,这种行为是否在英特尔标准中定义?
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
#include <emmintrin.h>
union SSE2
{
__m128i m_vector;
uint32_t m_dwords[sizeof(__m128i) / sizeof(uint32_t)];
};
int main()
{
union SSE2 reg = {_mm_set_epi32(INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX)};
reg.m_vector = _mm_add_epi32(reg.m_vector, _mm_set_epi32(1, 1, 1, 1));
printf("%08" PRIX32 "\n", (uint32_t) reg.m_dwords[0]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
[myria@polaris tests]$ gcc -m64 -msse2 -std=c11 -O3 sse2defined.c -o sse2defined
[myria@polaris tests]$ ./sse2defined
80000000
Run Code Online (Sandbox Code Playgroud)
请注意,SSE2的4字节大小的字段__m128i被视为已签名.
我正在尝试通过x86 mul指令执行64 = 32x32乘法,但是我只需要结果的高双字(edx寄存器)。因此,很自然地,我尝试将清单edx作为输出寄存器和eax破坏寄存器。
这对我来说似乎很自然,但eax它也是一个输入寄存器。当我尝试告诉GCC eax被破坏时,它会给出错误消息。
__asm__("mull\t%2" : "=d"(div10) : "%a"(UINT32_C(0x1999999A)), "r"(number)
: "cc", "rax");
Run Code Online (Sandbox Code Playgroud)
如果我尝试这样做,则会引发此错误消息:
divmod10.cpp:76:91: error: can’t find a register in class ‘AREG’ while reloading
‘asm’
divmod10.cpp:76:91: error: ‘asm’ operand has impossible constraints
Run Code Online (Sandbox Code Playgroud)
省略它可以编译,但是会破坏代码。GCC最终依赖于eax不被破坏,这是不正确的:
movl $429496730, %eax
#APP
# 76 "divmod10.cpp" 1
mull %esi
# 0 "" 2
#NO_APP
movl %edx, %esi
#APP
# 78 "divmod10.cpp" 1
mull %edx
# 0 "" 2
#NO_APP …Run Code Online (Sandbox Code Playgroud) 众所周知(尽管不够广泛>.<)C和C++没有指定评估函数参数的顺序.也就是说,puts()下面的两个s可以以任意顺序出现,作为任意编译器选择:
#include <cstdio>
int Function1() {
std::puts("Function1");
return 1;
}
int Function2() {
std::puts("Function2");
return 2;
}
int Add(int x, int y) {
return x + y;
}
int main() {
return Add(Function1(), Function2());
}
Run Code Online (Sandbox Code Playgroud)
然而,这是否也适用于评价this的左侧.,.*,->还是->*运营商?换句话说,puts()下面的顺序是否也未指定?
#include <cstdio>
struct Struct {
Struct() { std::puts("Struct::Struct"); }
int Member(int x) const { return x * 2; }
};
int Function() {
std::puts("Function");
return 14;
}
int …Run Code Online (Sandbox Code Playgroud) 在UNIX世界中,创建由RAM或页面文件而不是磁盘文件支持的文件映射对象的标准方法是调用shm_open。这将创建一个具有名称的内存映射,并返回可传递给的文件句柄mmap。
问题在于它创建了一个名称。如果我可以创建一个匿名内存映射,那就太好了。这将解决两个问题:
shm_unlink之后立即调用shm_open是一种可能,但是这会留下一个小窗口,在该窗口中突然终止会将该对象保留到下次重新启动为止。在Linux中,有memfd_create解决此问题的方法。同样,Windows允许传递一个空名称CreateFileMappingW来创建匿名映射。
Mac OS是否具有等效功能?
我在 Visual Studio 2017 15.6.2 中创建了一个全新的 Android 原生项目,并且没有更改单个项目设置或源代码行,点击构建。它失败并出现以下错误:
1>------ Build started: Project: AndroidNDKTest.NativeActivity, Configuration: Debug x86 ------
1>ANDROID_HOME=C:\Program Files (x86)\Android\android-sdk
1>ANT_HOME=
1>JAVA_HOME=C:\Program Files\Java\jdk1.8.0_161
1>NDK_ROOT=C:\ProgramData\Microsoft\AndroidNDK64\android-ndk-r13b
1>pch.h
1>TRACKER : error TRK0005: Failed to locate: "clang.exe". The system cannot find the file specified.
Run Code Online (Sandbox Code Playgroud)
不知道为什么找不到clang.exe,因为它存在:
C:\>dir /s C:\ProgramData\Microsoft\AndroidNDK64\android-ndk-r13b\clang.exe
Volume in drive C is OSDisk
Volume Serial Number is 1234-ABCD
Directory of C:\ProgramData\Microsoft\AndroidNDK64\android-ndk-r13b\toolchains\llvm\prebuilt\windows-x86_64\bin
03/08/2017 03:24 PM 43,847,680 clang.exe
Run Code Online (Sandbox Code Playgroud) 在ARM64汇编代码中,寄存器号31什么时候表示XZR,什么时候表示SP?
是否存在ARM C编译器的内在函数来执行随身携带操作,或者是否需要使用汇编语言?
在x86上,有_addcarry_u64for-carry-carry.(_addcarryx_u64特殊目的还有更新的.)
在C11,C++ 11和C++ 14中执行以下操作是否合法?
static_assert(((-4) >> 1) == -2, "my code assumes sign-extending right shift");
Run Code Online (Sandbox Code Playgroud)
或等效的C:
_Static_assert(((-4) >> 1) == -2, "my code assumes sign-extending right shift");
Run Code Online (Sandbox Code Playgroud)
我不知道关于是否可以使用如上所述的实现定义的操作的常量表达式的规则.
我知道,无论机器类型如何,相反的,带负数的左移符号都是未定义的.
Windows NT 有一个很好的函数GetCurrentThreadId,它的名字暗示了它的作用。它的实现非常快,因为它只是从线程本地存储中读取一个变量,该变量在 NT 内核创建线程期间写入那里。我想在 Linux 中实现它,但我遇到了一个障碍。
我最初的实现是这样的:
typedef pid_t ThreadID;
ThreadID GetCurrentThreadId(void)
{
static __thread ThreadID t_cachedID = (ThreadID) -1;
if (__builtin_expect(t_cachedID == (ThreadID) -1, 0))
{
t_cachedID = (ThreadID) syscall(__NR_gettid);
}
return t_cachedID;
}
Run Code Online (Sandbox Code Playgroud)
问题是fork。在程序,使用fork,t_cachedID变得陈旧-新的子进程的主线程有线程的线程本地存储的副本叫fork,那t_cachedID就是不再正确。
解决方案应该是pthread_atfork,以便t_cachedID将新子进程中的值更改为 -1,但作为 Pthreads API 的规范,它的设计很差。如果你是被使用卸载一个DLL dlclose,pthread_atfork不知道这一点,仍然会尽力呼吁一个你的函数fork,并KABOOM。糟糕的设计决策#1。也没有 API 可以删除您的回调函数。糟糕的设计决策#2。
有一个模糊记录的 glibc 函数__register_atfork似乎旨在处理这个问题,但它需要一个 DLL 句柄,而不是提供一种删除*_atfork处理程序的方法。glibc 在尝试解决 POSIX 糟糕的设计决策时做出的糟糕的设计决策 #1。
如何获得我自己的 …
我想触发一个有意的未定义操作码异常。ARM64 是否有像 x86ud2和 ARM32一样显式保留为未定义的指令udf?
当你释放内存时,指向内存的指针会发生什么?他们立即变得无效吗?如果他们以后再次有效会怎么样?
当然,指针变为无效然后再次变为"有效"的通常情况是将其他对象分配到之前使用的内存,如果使用指针访问内存,那么这显然是未定义的行为.悬空指针内存覆盖了第1课,差不多.
但是如果内存再次对同一个分配有效呢?只有一种标准方式可以实现:realloc().如果你有一个指向malloc()偏移量'd存储块内某处的指针> 1,那么使用realloc()缩小块到小于你的偏移量,显然你的指针变得无效.如果你再次使用realloc()增长块至少覆盖悬空指针指向的对象类型,并且在任何情况下都没有realloc()移动内存块,悬空指针是否再次有效?
这是一个极端的案例,我真的不知道如何解释C或C++标准来解决它.以下是显示它的程序.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
static const char s_message[] = "hello there";
static const char s_kitty[] = "kitty";
char *string = malloc(sizeof(s_message));
if (!string)
{
fprintf(stderr, "malloc failed\n");
return 1;
}
memcpy(string, s_message, sizeof(s_message));
printf("%p %s\n", string, string);
char *overwrite = string + 6;
*overwrite = '\0';
printf("%p %s\n", string, string);
string[4] = '\0';
char *new_string = …Run Code Online (Sandbox Code Playgroud) 当我尝试在GCC或clang中编译它时,我收到一个错误.
#include <cstddef>
template <void (*Function)()>
void Wrapper()
{
}
int main()
{
void (*meow)() = Wrapper<NULL>;
return meow ? 1 : 0;
}
Run Code Online (Sandbox Code Playgroud)
$ g++ -m64 -std=c++11 -c nulltemplate.cpp
nulltemplate.cpp: In function ‘int main()’:
nulltemplate.cpp:10:19: error: no matches converting function ‘Wrapper’ to type ‘void (*)()’
nulltemplate.cpp:4:6: error: candidate is: template<void (* Function)()> void Wrapper()
Run Code Online (Sandbox Code Playgroud)
为什么我不能这样做?错误的措辞就好像Wrapper是一个无法在上下文中解析为特定函数指针类型的重载,这对我来说没有意义.