c - 堆栈上的常量数据?
问题描述
我要回答某人关于 printf 接受 char * 的问题,所以我构建了一个小测试程序并有我自己的问题。使用 GCC 6.3 在 codechef.com/ide 上编译
将 char* 直接传递给 printf 我认为问题是在询问“缺少”的 const 限定符发生了什么,对吗? http://man7.org/linux/man-pages/man3/printf.3.html
char * str1 = "This is string 1\n";
char str2[] = "This is string 2\n";
int main(void) {
char str3[100] = "This is string 3\n";
char * str4 = "This is string 4\n";
str3[8] = 'c';
printf(str1);
printf(str2);
printf(str3);
printf(str4);
return 0;
}
输出:
这是字符串 1
这是一个字符串 2
这是字符串 3
这是字符串 4
我正在考虑程序的内存布局,我更加困惑。 https://www.geeksforgeeks.org/memory-layout-of-c-program/
str1 是指向字符串文字“这是字符串 1\n”的指针。str1 存在于数据中并指向存在于 ?? 中的字符串文字。(我假设也初始化数据段) 只读存储器是如何在 C 中实现的?
就内存布局而言,str2 类似于 str1。
str3 是有趣的地方。str3 位于堆栈上,100 个字符宽,并通过声明/分配分配 char[0] = 'T'、char[1] = 'h' 等。这不应该是 CONST。str3 的声明和赋值是在堆栈上声明 100 个字符并从数据(ROM 数据段或初始化的数据段或文本?)中为它们分配值。
str4 是栈上的指针,指向数据段内存。这就像 str1 和 str2,不太有趣。
然后分配 str3[8] = 'c' 只是为了测试/验证/证明 str3 的堆栈内存在 printfing 之前不是只读的。
我希望 1,2,4 可以工作,但是为什么 3 可以工作(甚至没有编译器警告???)。我可能错误地假设 const 是“只读”的同义词,因为如果我只是写它,str3 就不可能是“只读”的。
谁能向我解释为什么 str3 没有抛出警告或错误?str3 不是 const char *,要么编译器对其进行了优化(将赋值更改为“这是 ctring 3\n”),要么警告被抑制(似乎也不太可能),或者我对 cost 关键字有根本的误解. 堆栈内存常量如何?也许我的一个或多个假设是错误的。
解决方案
当函数原型包含指向const
-qualified 对象的指针时,这意味着函数承诺不会尝试修改指向的内容。这并不意味着只能接受指向const
对象的指针(无论可能是什么)。
另一方面,如果原型包含一个指向非 const
限定对象的指针,这意味着它可能会尝试修改内容。在这种情况下,将指针传递给不可变对象会导致未定义行为。如果您尝试将指针传递给const
-qualified 对象(如果启用警告),大多数编译器会警告您,因为const
-qualified 指针可能指向不可变对象。
一般来说,您应该认为const
是“我保证不修改这个”而不是“这个不能修改”。
推荐阅读
- javascript - 运算符在 React JS 中的行为异常
- android - 模拟 ApolloClient 的查询(调用)以进行测试
- javascript - 在循环中显示数据,而不是全部循环,每个数据都会中断
- r - 如何从ggplot2中的列中绘制某些值的条形图?将从数据框中自动选择值
- vue.js - 错误:vue-loader 要求 @vue/compiler-sfc 存在于依赖树中
- sql - 在 SQL Server 中使用 Like 语句搜索 FirstName 和 LastName
- c++ - 使用 windeployqt 在构建后事件中复制 Qt dll 不起作用
- django - Django 迁移 sqlmigrate
- hibernate - Hibernate Envers OneToMany Cascade.ALL org.hibernate.HibernateException:找到了多个具有给定标识符的行
- linux - 编译当前 Kerberos 版本时错误在哪里?