我已经使用 C 指针有一段时间了,一切都按预期工作。然而现在我遇到了 ISO 标准,该标准规定“如果生成的指针未针对指向的类型正确对齐,则行为未定义”。
这让我不禁要问自己:
这是什么意思?
我们如何安全地将指针转换为其他类型?
我发现这个 C 代码示例据说是不正确的,因为它与更严格对齐的指针类型有关:
int main() {
char c = 'x';
int *ip = (int *)&c;
char *cp = (char *)ip;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我的系统:在 x86_64 上运行的 Ubuntu 22.04.3。海湾合作委员会版本 11.4.0
我读到 System V ABI 强制要求使用红色区域。来自海湾合作委员会手册:
红色区域是 x86-64 ABI 强制规定的,它是超出堆栈指针位置的 128 字节区域,不会被信号或中断处理程序修改,因此可用于临时数据而无需调整堆栈指针。该标志
-mno-red-zone禁用该红色区域。
我的问题:
如果我在 gcc 中使用该标志,红色区域是否仍然存在-mno-red-zone?
如果红色区域被“禁用”,这是否意味着我不再遵守系统 V ABI?
这会产生什么后果(不符合 System V ABI)?
我知道在 C 中,当涉及到指针参数时,我们有两种不同类型的语法。我只是想知道它们是否真的一样。考虑这个小程序,其中我有两个函数 fx1 和 fx2,它们采用具有不同 sintax 的指针参数:
void fx1( int* p ){
*p = 10;
}
void fx2( int p[] ){
*p = 10;
}
int main(){
int a = 20;
fx1(&a);
fx2(&a);
Run Code Online (Sandbox Code Playgroud) 尽管我知道这个主题的范围要广泛得多,但我处于 Linux 环境中
假设我正在编写一个简单的 C 程序,并且想向终端写入“Hello”。显而易见的方法是使用 C 标准库 printf,它又使用 write 系统调用(包装函数而不是系统调用本身),而 write 系统调用又调用实际的汇编系统调用指令(或 int)。不太明显的方法是在我的 C 源文件中使用一些内联汇编,或者直接创建一个包含系统调用指令的汇编文件。
似乎在一天结束时,我们以某种方式结束了系统调用(指令 syscall 或 int)。这是唯一的方法吗?
在现代 PC 中,术语“应用程序”与“用户程序”的含义相同吗?
我编写的 PowerPoint、Google Chrome、Visual Studio Code、Photoshop 或 C 程序都是需要系统调用来请求操作系统服务以执行写入文件等特权操作的应用程序/用户程序的示例,这样说是否正确?
考虑这段代码:
char *test() {
return "HELLO";
}
int main() {
char *p = test();
printf("%s\n", p);
}
Run Code Online (Sandbox Code Playgroud)
这会在没有警告的情况下进行编译,我猜是因为"HELLO"它没有存储在堆栈中。但这给了我一个警告:
char *test() {
char arr[] = "HELLO";
return arr;
}
int main() {
char *p = test();
printf("%s\n", p);
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
字符串文字真的存储在称为字符串文字池的区域中吗?
如果是这样,存储在字符串文字池中的数据是否可以被视为全局数据?
从函数返回字符串文字总是安全的(因为它是全局的)?
我知道C程序在内存中的基本布局是代码/文本、数据、堆和堆栈。C 程序内存布局确实对应于内存中进程的更一般布局。
我的问题是:
“C 程序布局 = 通用过程布局”关联源自何处?(如果我们考虑所有的计算机科学文献......)
如果我要为我创建的编程语言(让我们称之为“ONE”)编写一个编译器,我应该遵守哪些主要规则(假设我们使用的是带有 intel x86_64 的 Linux 操作系统)?
c ×5
linux ×2
pointers ×2
abi ×1
arrays ×1
assembly ×1
c-strings ×1
casting ×1
executable ×1
kernel-mode ×1
lifetime ×1
memory ×1
red-zone ×1
stack-memory ×1
system-calls ×1
unix ×1
usermode ×1
x86-64 ×1