我一直在尝试用c ++创建自己的二进制文件。我正在做的是定义了一个结构,该结构实际上与dds标头相同。因此,我要做的是首先向二进制文件中写入一个版本号,以查看我处于什么阶段,然后将整个结构写入文件,最后将一个简单的文本字符串写入文件。 但是,当我尝试将版本号写入文件时,会引发如下异常:“在TestApplication7.exe中,在0x0F377236(msvcp140d.dll)处引发了异常:0xC0000005:访问冲突读取位置0x499602DB。”
所以基本上我正在做的是像这样在cpp文件的顶部定义一个版本号:
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
@Slf4j
public class SecurityConfig {
@Bean
public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
return http
.csrf().disable()
.httpBasic().disable()
.formLogin().disable()
.logout().disable()
.authenticationManager(this.authenticationManager())
.securityContextRepository(this.securityContextRepository())
.authorizeExchange().pathMatchers("/public/**").permitAll()
.and().authorizeExchange().anyExchange().authenticated()
.and().build();
}
@Bean
ReactiveAuthenticationManager authenticationManager() {
return authentication -> {
log.debug("Autentication: " + authentication.toString());
if (authentication instanceof CustomPreAuthenticationToken) {
authentication.setAuthenticated(true);
}
return Mono.just(authentication);
};
}
@Bean
ServerSecurityContextRepository securityContextRepository() {
return new ServerSecurityContextRepository() {
@Override
public Mono<Void> save(ServerWebExchange serverWebExchange, SecurityContext securityContext) {
return null;
}
@Override
public Mono<SecurityContext> load(ServerWebExchange serverWebExchange) {
Principal nonReactivePrincipal = getPrincipalFromExchangeUsingReflection(serverWebExchange);
return Mono.just(new SecurityContextImpl(new CustomPreAuthenticationToken(nonReactivePrincipal.getName(), nonReactivePrincipal, AuthorityUtils.createAuthorityList("ROLE_USER") )));
}
};
}
private Principal getPrincipalFromExchangeUsingReflection(ServerWebExchange serverWebExchange) {
Principal principal = null;
try {
Field ServletServerHttpRequestField = serverWebExchange.getClass().getDeclaredField("request");
ServletServerHttpRequestField.setAccessible(true);
Object servletServerHttpRequest = ServletServerHttpRequestField.get(serverWebExchange);
Field httpServletRequestField = servletServerHttpRequest.getClass().getDeclaredField("request");
httpServletRequestField.setAccessible(true);
HttpServletRequest httpServletRequest = (HttpServletRequest) httpServletRequestField.get(servletServerHttpRequest);
principal = httpServletRequest.getUserPrincipal();
} catch (IllegalAccessException | NoSuchFieldException e) {
log.error(e.getMessage(), e);
}
return principal;
}
}
public class CustomPreAuthenticationToken extends UsernamePasswordAuthenticationToken {
public CustomPreAuthenticationToken(String key, Object principal, Collection<? extends GrantedAuthority> authorities) {
super(key, principal, authorities);
}
}
然后我只是简单地尝试将此数字写入二进制文件。
这是我的示例代码:
#define VERSION_NR 0x499602DB
所以是这样的代码:
void MyFile::Save(std::string ddsPath, MyFile::FileHeader header, const std::string texturePath) {
header.PathLen = texturePath.length();
const char* buffer{reinterpret_cast<const char*>(&texturePath)};
const char* version{reinterpret_cast<const char*>(VERSION_NR)};
std::ofstream output(ddsPath, std::ios::binary);
output.write(version, sizeof(VERSION_NR)); //Here is where the exception is thrown
ext->WriteStruct(output, header); //Writing the hole header to the file
output << texturePath; //Outputting a simple text to the file
}
这导致引发异常,我不知道自己在做什么错,因为我对C ++编程非常陌生。我确实尝试在“保存”方法中创建一个const DWORD而不是使用宏,但是我仍然遇到相同的异常。 我不知道这是否有帮助,但消息“访问冲突读取位置0x499602DB”与我的宏的值是相同的“位置”。
如果有人可以帮助我,或者只是将我指出正确的方向,我将不胜感激。 谢谢!
答案 0 :(得分:2)
如果我们摆脱了宏和许多其他不相关的代码,我们将得到:
int version = 0x499602DB;
const char* ch = reinterpret_cast<const char*>(version);
std::ofstream output("out.bin", std::ios::binary);
output.write(ch, sizeof(version));
您是正确的,即错误消息中显示了您的版本值这一事实是一个线索。第二行将整数值转换为地址为0x499602DB
的字符指针。由于output.write
尝试访问该地址时,该地址未指向有效的内存地址,因此操作系统不允许该操作,并且引发和访问冲突。
正确的代码是:
int version = 0x499602DB;
const char* ch = reinterpret_cast<const char*>(&version);
std::ofstream output("out.bin", std::ios::binary);
output.write(ch, sizeof(version));
或者,无论如何,您都想编写一个字符串,只需避免全部强制转换:
const char version[4] = {'\xDB','\x02','\x96','\x49'};
std::ofstream output("out.bin", std::ios::binary);
output.write(version, sizeof(version));
还请注意,一旦我们解决了此崩溃问题,以下内容也不正确:
const char* buffer{reinterpret_cast<const char*>(&texturePath)};
并且应该简单地是:
const char* buffer = texturePath.c_str();
texturePath
是一个std::string
对象,指向它的指针不能转换为char*
,c_str()
方法返回一个const char*
指针,然后可以传递该指针到std::ofstream::write
的位置,或者只需像现在一样使用output << texturePath
,然后删除buffer
变量即可。
答案 1 :(得分:1)
VERSION_NR不是变量,因此char *指向随机存储器。 不要像处理其他数据那样使用宏,创建变量,在其上获取指针。